QOF  0.7.5
qofquerycore.c
1 /********************************************************************\
2  * QueryCore.c -- API for providing core Query data types *
3  * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
4  * Copyright (C) 2006 Neil Williams <linux@codehelp.co.uk> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <glib.h>
28 
29 #include "qof.h"
30 #include "qofquerycore-p.h"
31 
32 static QofLogModule log_module = QOF_MOD_QUERY;
33 
34 /* A function to destroy a query predicate's pdata */
35 typedef void (*QueryPredDataFree) (QofQueryPredData * pdata);
36 
37 /* A function to copy a query's predicate data */
38 typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData *
39  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 gchar *(*QueryToString) (gpointer object, QofParam * getter);
48 
49 /* A function to test for equality of predicate data */
50 typedef gboolean (*QueryPredicateEqual) (QofQueryPredData * p1,
51  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 gchar *(*query_string_getter) (gpointer, QofParam *);
58 static const gchar *query_string_type = QOF_TYPE_STRING;
59 
60 typedef QofTime *(*query_time_getter) (gpointer, QofParam *);
61 static const gchar *query_time_type = QOF_TYPE_TIME;
62 
63 typedef QofNumeric (*query_numeric_getter) (gpointer, QofParam *);
64 static const gchar *query_numeric_type = QOF_TYPE_NUMERIC;
65 
66 typedef GList *(*query_glist_getter) (gpointer, QofParam *);
67 typedef const GUID *(*query_guid_getter) (gpointer, QofParam *);
68 static const gchar *query_guid_type = QOF_TYPE_GUID;
69 
70 typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
71 static const gchar *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 gchar *query_double_type = QOF_TYPE_DOUBLE;
78 
79 typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
80 static const gchar *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 KvpFrame *(*query_kvp_getter) (gpointer, QofParam *);
86 static const gchar *query_kvp_type = QOF_TYPE_KVP;
87 
88 typedef QofCollection *(*query_collect_getter) (gpointer, QofParam *);
89 static const gchar *query_collect_type = QOF_TYPE_COLLECT;
90 
91 typedef const GUID *(*query_choice_getter) (gpointer, QofParam *);
92 static const gchar *query_choice_type = QOF_TYPE_CHOICE;
93 
94 /* Tables for predicate storage and lookup */
95 static gboolean initialized = FALSE;
96 static GHashTable *predTable = NULL;
97 static GHashTable *cmpTable = NULL;
98 static GHashTable *copyTable = NULL;
99 static GHashTable *freeTable = NULL;
100 static GHashTable *toStringTable = NULL;
101 static GHashTable *predEqualTable = NULL;
102 
103 #define COMPARE_ERROR -3
104 #define PREDICATE_ERROR -2
105 
106 #define VERIFY_PDATA(str) { \
107  g_return_if_fail (pd != NULL); \
108  g_return_if_fail (pd->type_name == str || \
109  !safe_strcmp (str, pd->type_name)); \
110 }
111 #define VERIFY_PDATA_R(str) { \
112  g_return_val_if_fail (pd != NULL, NULL); \
113  g_return_val_if_fail (pd->type_name == str || \
114  !safe_strcmp (str, pd->type_name), \
115  NULL); \
116 }
117 #define VERIFY_PREDICATE(str) { \
118  g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
119  g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
120  g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
121  g_return_val_if_fail (pd->type_name == str || \
122  !safe_strcmp (str, pd->type_name), \
123  PREDICATE_ERROR); \
124 }
125 
126 /* *******************************************************************/
127 /* TYPE-HANDLING FUNCTIONS */
128 
129 /* QOF_TYPE_STRING */
130 
131 static gint
132 string_match_predicate (gpointer object,
133  QofParam * getter, QofQueryPredData * pd)
134 {
135  query_string_t pdata = (query_string_t) pd;
136  const gchar *s;
137  gint ret = 0;
138 
139  VERIFY_PREDICATE (query_string_type);
140 
141  s = ((query_string_getter) getter->param_getfcn) (object, getter);
142 
143  if (!s)
144  s = "";
145 
146  if (pdata->is_regex)
147  {
148  regmatch_t match;
149  if (!regexec (&pdata->compiled, s, 1, &match, 0))
150  ret = 1;
151 
152  }
153  else if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE)
154  {
155  if (strcasestr (s, pdata->matchstring))
156  ret = 1;
157 
158  }
159  else
160  {
161  if (strstr (s, pdata->matchstring))
162  ret = 1;
163  }
164 
165  switch (pd->how)
166  {
167  case QOF_COMPARE_EQUAL:
168  return ret;
169  case QOF_COMPARE_NEQ:
170  return !ret;
171  default:
172  PWARN ("bad match type: %d", pd->how);
173  return 0;
174  }
175 }
176 
177 static gint
178 string_compare_func (gpointer a, gpointer b, gint options,
179  QofParam * getter)
180 {
181  const gchar *s1, *s2;
182  g_return_val_if_fail (a && b && getter
183  && getter->param_getfcn, COMPARE_ERROR);
184 
185  s1 = ((query_string_getter) getter->param_getfcn) (a, getter);
186  s2 = ((query_string_getter) getter->param_getfcn) (b, getter);
187 
188  if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
189  return safe_strcasecmp (s1, s2);
190 
191  return safe_strcmp (s1, s2);
192 }
193 
194 static void
195 string_free_pdata (QofQueryPredData * pd)
196 {
197  query_string_t pdata = (query_string_t) pd;
198 
199  VERIFY_PDATA (query_string_type);
200 
201  if (pdata->is_regex)
202  regfree (&pdata->compiled);
203  else
204  g_free (pdata->matchstring);
205 
206  g_free (pdata);
207 }
208 
209 static QofQueryPredData *
210 string_copy_predicate (QofQueryPredData * pd)
211 {
212  query_string_t pdata = (query_string_t) pd;
213 
214  VERIFY_PDATA_R (query_string_type);
215 
216  return qof_query_string_predicate (pd->how, pdata->matchstring,
217  pdata->options, pdata->is_regex);
218 }
219 
220 static gboolean
221 string_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
222 {
223  query_string_t pd1 = (query_string_t) p1;
224  query_string_t pd2 = (query_string_t) p2;
225 
226  if (pd1->options != pd2->options)
227  return FALSE;
228  if (pd1->is_regex != pd2->is_regex)
229  return FALSE;
230  return (safe_strcmp (pd1->matchstring, pd2->matchstring) == 0);
231 }
232 
234 qof_query_string_predicate (QofQueryCompare how,
235  const gchar *str, QofStringMatch options, gboolean is_regex)
236 {
237  query_string_t pdata;
238 
239  g_return_val_if_fail (str, NULL);
240  g_return_val_if_fail (*str != '\0', NULL);
241  g_return_val_if_fail (how == QOF_COMPARE_EQUAL
242  || how == QOF_COMPARE_NEQ, NULL);
243 
244  pdata = g_new0 (query_string_def, 1);
245  pdata->pd.type_name = query_string_type;
246  pdata->pd.how = how;
247  pdata->options = options;
248  pdata->matchstring = g_strdup (str);
249 
250  if (is_regex)
251  {
252  int flags = REG_EXTENDED;
253  if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
254  flags |= REG_ICASE;
255 
256  regcomp (&pdata->compiled, str, flags);
257  pdata->is_regex = TRUE;
258  }
259 
260  return ((QofQueryPredData *) pdata);
261 }
262 
263 static gchar *
264 string_to_string (gpointer object, QofParam * getter)
265 {
266  const char *res;
267  res = ((query_string_getter) getter->param_getfcn) (object, getter);
268  if (res)
269  return g_strdup (res);
270  return NULL;
271 }
272 
273 /* QOF_TYPE_TIME */
274 
275 static gint
276 time_compare (QofTime *ta, QofTime *tb, QofDateMatch options)
277 {
278  if (options == QOF_DATE_MATCH_DAY)
279  {
282  }
283  return qof_time_cmp (ta, tb);
284 }
285 
286 static int
287 time_match_predicate (gpointer object, QofParam * getter,
288  QofQueryPredData * pd)
289 {
290  query_time_t pdata = (query_time_t) pd;
291  QofTime *objtime;
292  gint compare;
293 
294  VERIFY_PREDICATE (query_time_type);
295 
296  objtime = ((query_time_getter) getter->param_getfcn) (object, getter);
297  compare = time_compare (objtime, pdata->qt, pdata->options);
298 
299  switch (pd->how)
300  {
301  case QOF_COMPARE_LT:
302  return (compare < 0);
303  case QOF_COMPARE_LTE:
304  return (compare <= 0);
305  case QOF_COMPARE_EQUAL:
306  return (compare == 0);
307  case QOF_COMPARE_GT:
308  return (compare > 0);
309  case QOF_COMPARE_GTE:
310  return (compare >= 0);
311  case QOF_COMPARE_NEQ:
312  return (compare != 0);
313  default:
314  PWARN ("bad match type: %d", pd->how);
315  return 0;
316  }
317 }
318 
319 static gint
320 time_compare_func (gpointer a, gpointer b, gint options,
321  QofParam * getter)
322 {
323  QofTime *ta, *tb;
324 
325  g_return_val_if_fail (a && b && getter
326  && getter->param_getfcn, COMPARE_ERROR);
327 
328  ta = ((query_time_getter) getter->param_getfcn) (a, getter);
329  tb = ((query_time_getter) getter->param_getfcn) (b, getter);
330 
331  return time_compare (ta, tb, options);
332 }
333 
334 static void
335 time_free_pdata (QofQueryPredData * pd)
336 {
337  query_time_t pdata = (query_time_t) pd;
338 
339  VERIFY_PDATA (query_time_type);
340 
341  g_free (pdata);
342 }
343 
344 static QofQueryPredData *
345 time_copy_predicate (QofQueryPredData * pd)
346 {
347  query_time_t pdata = (query_time_t) pd;
348 
349  VERIFY_PDATA_R (query_time_type);
350 
351  return qof_query_time_predicate (pd->how, pdata->options,
352  pdata->qt);
353 }
354 
355 static gboolean
356 time_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
357 {
358  query_time_t pd1 = (query_time_t) p1;
359  query_time_t pd2 = (query_time_t) p2;
360 
361  if (pd1->options != pd2->options)
362  return FALSE;
363  return qof_time_equal (pd1->qt, pd2->qt);
364 }
365 
367 qof_query_time_predicate (QofQueryCompare how,
368  QofDateMatch options, QofTime *qt)
369 {
370  query_time_t pdata;
371 
372  pdata = g_new0 (query_time_def, 1);
373  pdata->pd.type_name = query_time_type;
374  pdata->pd.how = how;
375  pdata->options = options;
376  pdata->qt = qt;
377  return ((QofQueryPredData *) pdata);
378 }
379 
380 gboolean
382  QofTime *qt)
383 {
384  query_time_t pdata = (query_time_t) pd;
385 
386  if (pdata->pd.type_name != query_time_type)
387  return FALSE;
388  qt = pdata->qt;
389  return TRUE;
390 }
391 
392 static gchar *
393 time_to_string (gpointer object, QofParam * getter)
394 {
395  QofDate *qd;
396  QofTime *qt =
397  ((query_time_getter) getter->param_getfcn) (object, getter);
398 
399  qd = qof_date_from_qtime (qt);
400  return qof_date_print (qd, QOF_DATE_FORMAT_UTC);
401 }
402 
403 /* QOF_TYPE_NUMERIC ================================================= */
404 
405 static int
406 numeric_match_predicate (gpointer object, QofParam * getter,
407  QofQueryPredData * pd)
408 {
409  query_numeric_t pdata = (query_numeric_t) pd;
410  QofNumeric obj_val;
411  gint compare;
412 
413  VERIFY_PREDICATE (query_numeric_type);
414 
415  obj_val =
416  ((query_numeric_getter) getter->param_getfcn) (object, getter);
417 
418  switch (pdata->options)
419  {
420  case QOF_NUMERIC_MATCH_CREDIT:
421  if (qof_numeric_positive_p (obj_val))
422  return 0;
423  break;
424  case QOF_NUMERIC_MATCH_DEBIT:
425  if (qof_numeric_negative_p (obj_val))
426  return 0;
427  break;
428  default:
429  break;
430  }
431 
432  /* Amounts are considered to be 'equal' if they match to
433  * four decimal places. (epsilon=1/10000) */
434  if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ)
435  {
436  QofNumeric cmp_val = qof_numeric_create (1, 10000);
437  compare =
439  (qof_numeric_sub (qof_numeric_abs (obj_val),
440  qof_numeric_abs (pdata->
441  amount),
442  100000, QOF_HOW_RND_ROUND)), cmp_val) < 0);
443  }
444  else
445  compare =
446  qof_numeric_compare (qof_numeric_abs (obj_val), pdata->amount);
447 
448  switch (pd->how)
449  {
450  case QOF_COMPARE_LT:
451  return (compare < 0);
452  case QOF_COMPARE_LTE:
453  return (compare <= 0);
454  case QOF_COMPARE_EQUAL:
455  return compare;
456  case QOF_COMPARE_GT:
457  return (compare > 0);
458  case QOF_COMPARE_GTE:
459  return (compare >= 0);
460  case QOF_COMPARE_NEQ:
461  return !compare;
462  default:
463  PWARN ("bad match type: %d", pd->how);
464  return 0;
465  }
466 }
467 
468 static int
469 numeric_compare_func (gpointer a, gpointer b,
470  gint options __attribute__ ((unused)), QofParam * getter)
471 {
472  QofNumeric va, vb;
473 
474  g_return_val_if_fail (a && b && getter
475  && getter->param_getfcn, COMPARE_ERROR);
476 
477  va = ((query_numeric_getter) getter->param_getfcn) (a, getter);
478  vb = ((query_numeric_getter) getter->param_getfcn) (b, getter);
479 
480  return qof_numeric_compare (va, vb);
481 }
482 
483 static void
484 numeric_free_pdata (QofQueryPredData * pd)
485 {
486  query_numeric_t pdata = (query_numeric_t) pd;
487  VERIFY_PDATA (query_numeric_type);
488  g_free (pdata);
489 }
490 
491 static QofQueryPredData *
492 numeric_copy_predicate (QofQueryPredData * pd)
493 {
494  query_numeric_t pdata = (query_numeric_t) pd;
495  VERIFY_PDATA_R (query_numeric_type);
496  return qof_query_numeric_predicate (pd->how, pdata->options,
497  pdata->amount);
498 }
499 
500 static gboolean
501 numeric_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
502 {
503  query_numeric_t pd1 = (query_numeric_t) p1;
504  query_numeric_t pd2 = (query_numeric_t) p2;
505 
506  if (pd1->options != pd2->options)
507  return FALSE;
508  return qof_numeric_equal (pd1->amount, pd2->amount);
509 }
510 
512 qof_query_numeric_predicate (QofQueryCompare how,
513  QofNumericMatch options, QofNumeric value)
514 {
515  query_numeric_t pdata;
516  pdata = g_new0 (query_numeric_def, 1);
517  pdata->pd.type_name = query_numeric_type;
518  pdata->pd.how = how;
519  pdata->options = options;
520  pdata->amount = value;
521  return ((QofQueryPredData *) pdata);
522 }
523 
524 static char *
525 numeric_to_string (gpointer object, QofParam * getter)
526 {
527  QofNumeric num;
528  num = ((query_numeric_getter) getter->param_getfcn) (object, getter);
529 
530  return qof_numeric_to_string (num);
531 }
532 
533 static char *
534 debcred_to_string (gpointer object, QofParam * getter)
535 {
536  QofNumeric num;
537  num = ((query_numeric_getter) getter->param_getfcn) (object, getter);
538 
539  return qof_numeric_to_string (num);
540 }
541 
542 /* QOF_TYPE_GUID =================================================== */
543 
544 static int
545 guid_match_predicate (gpointer object, QofParam * getter,
546  QofQueryPredData * pd)
547 {
548  query_guid_t pdata = (query_guid_t) pd;
549  GList *node, *o_list;
550  const GUID *guid = NULL;
551 
552  VERIFY_PREDICATE (query_guid_type);
553 
554  switch (pdata->options)
555  {
556 
557  case QOF_GUID_MATCH_ALL:
558  /* object is a GList of objects; param_getfcn must be called on each one.
559  * See if every guid in the predicate is accounted-for in the
560  * object list
561  */
562 
563  for (node = pdata->guids; node; node = node->next)
564  {
565  /* See if this GUID matches the object's guid */
566  for (o_list = object; o_list; o_list = o_list->next)
567  {
568  guid =
569  ((query_guid_getter) getter->param_getfcn) (o_list->
570  data, getter);
571  if (guid_equal (node->data, guid))
572  break;
573  }
574 
575  /*
576  * If o_list is NULL, we've walked the whole list without finding
577  * a match. Therefore break out now, the match has failed.
578  */
579  if (o_list == NULL)
580  break;
581  }
582 
583  /*
584  * The match is complete. If node == NULL then we've succesfully
585  * found a match for all the guids in the predicate. Return
586  * appropriately below.
587  */
588 
589  break;
590 
592  /* object is a single object, getter returns a GList* of GUID*
593  *
594  * See if any GUID* in the returned list matches any guid in the
595  * predicate match list.
596  */
597 
598  o_list =
599  ((query_glist_getter) getter->param_getfcn) (object, getter);
600 
601  for (node = o_list; node; node = node->next)
602  {
603  GList *node2;
604 
605  /* Search the predicate data for a match */
606  for (node2 = pdata->guids; node2; node2 = node2->next)
607  {
608  if (guid_equal (node->data, node2->data))
609  break;
610  }
611 
612  /* Check to see if we found a match. If so, break now */
613  if (node2 != NULL)
614  break;
615  }
616 
617  g_list_free (o_list);
618 
619  /* yea, node may point to an invalid location, but that's ok.
620  * we're not _USING_ the value, just checking that it's non-NULL
621  */
622 
623  break;
624 
625  default:
626  /* object is a single object, getter returns a GUID*
627  *
628  * See if the guid is in the list
629  */
630 
631  guid = ((query_guid_getter) getter->param_getfcn) (object, getter);
632  for (node = pdata->guids; node; node = node->next)
633  {
634  if (guid_equal (node->data, guid))
635  break;
636  }
637  }
638 
639  switch (pdata->options)
640  {
641  case QOF_GUID_MATCH_ANY:
643  return (node != NULL);
644  break;
645  case QOF_GUID_MATCH_NONE:
646  case QOF_GUID_MATCH_ALL:
647  return (node == NULL);
648  break;
649  case QOF_GUID_MATCH_NULL:
650  return (guid == NULL);
651  break;
652  default:
653  PWARN ("bad match type");
654  return 0;
655  }
656 }
657 
658 static void
659 guid_free_pdata (QofQueryPredData * pd)
660 {
661  query_guid_t pdata = (query_guid_t) pd;
662  GList *node;
663  VERIFY_PDATA (query_guid_type);
664  for (node = pdata->guids; node; node = node->next)
665  {
666  guid_free (node->data);
667  }
668  g_list_free (pdata->guids);
669  g_free (pdata);
670 }
671 
672 static QofQueryPredData *
673 guid_copy_predicate (QofQueryPredData * pd)
674 {
675  query_guid_t pdata = (query_guid_t) pd;
676  VERIFY_PDATA_R (query_guid_type);
677  return qof_query_guid_predicate (pdata->options, pdata->guids);
678 }
679 
680 static gboolean
681 guid_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
682 {
683  query_guid_t pd1 = (query_guid_t) p1;
684  query_guid_t pd2 = (query_guid_t) p2;
685  GList *l1 = pd1->guids, *l2 = pd2->guids;
686 
687  if (pd1->options != pd2->options)
688  return FALSE;
689  if (g_list_length (l1) != g_list_length (l2))
690  return FALSE;
691  for (; l1; l1 = l1->next, l2 = l2->next)
692  {
693  if (!guid_equal (l1->data, l2->data))
694  return FALSE;
695  }
696  return TRUE;
697 }
698 
700 qof_query_guid_predicate (QofGuidMatch options, GList * guid_list)
701 {
702  query_guid_t pdata;
703  GList *node;
704 
705  if (NULL == guid_list)
706  return NULL;
707 
708  pdata = g_new0 (query_guid_def, 1);
709  pdata->pd.how = QOF_COMPARE_EQUAL;
710  pdata->pd.type_name = query_guid_type;
711  pdata->options = options;
712 
713  pdata->guids = g_list_copy (guid_list);
714  for (node = pdata->guids; node; node = node->next)
715  {
716  GUID *guid = guid_malloc ();
717  *guid = *((GUID *) node->data);
718  node->data = guid;
719  }
720  return ((QofQueryPredData *) pdata);
721 }
722 
723 /* ================================================================ */
724 /* QOF_TYPE_INT32 */
725 
726 static int
727 int32_match_predicate (gpointer object, QofParam * getter,
728  QofQueryPredData * pd)
729 {
730  gint32 val;
731  query_int32_t pdata = (query_int32_t) pd;
732 
733  VERIFY_PREDICATE (query_int32_type);
734 
735  val = ((query_int32_getter) getter->param_getfcn) (object, getter);
736 
737  switch (pd->how)
738  {
739  case QOF_COMPARE_LT:
740  return (val < pdata->val);
741  case QOF_COMPARE_LTE:
742  return (val <= pdata->val);
743  case QOF_COMPARE_EQUAL:
744  return (val == pdata->val);
745  case QOF_COMPARE_GT:
746  return (val > pdata->val);
747  case QOF_COMPARE_GTE:
748  return (val >= pdata->val);
749  case QOF_COMPARE_NEQ:
750  return (val != pdata->val);
751  default:
752  PWARN ("bad match type: %d", pd->how);
753  return 0;
754  }
755 }
756 
757 static int
758 int32_compare_func (gpointer a, gpointer b,
759  gint options __attribute__ ((unused)),
760  QofParam * getter)
761 {
762  gint32 v1, v2;
763  g_return_val_if_fail (a && b && getter
764  && getter->param_getfcn, COMPARE_ERROR);
765 
766  v1 = ((query_int32_getter) getter->param_getfcn) (a, getter);
767  v2 = ((query_int32_getter) getter->param_getfcn) (b, getter);
768 
769  if (v1 < v2)
770  return -1;
771  if (v1 > v2)
772  return 1;
773  return 0;
774 }
775 
776 static void
777 int32_free_pdata (QofQueryPredData * pd)
778 {
779  query_int32_t pdata = (query_int32_t) pd;
780  VERIFY_PDATA (query_int32_type);
781  g_free (pdata);
782 }
783 
784 static QofQueryPredData *
785 int32_copy_predicate (QofQueryPredData * pd)
786 {
787  query_int32_t pdata = (query_int32_t) pd;
788  VERIFY_PDATA_R (query_int32_type);
789  return qof_query_int32_predicate (pd->how, pdata->val);
790 }
791 
792 static gboolean
793 int32_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
794 {
795  query_int32_t pd1 = (query_int32_t) p1;
796  query_int32_t pd2 = (query_int32_t) p2;
797 
798  return (pd1->val == pd2->val);
799 }
800 
802 qof_query_int32_predicate (QofQueryCompare how, gint32 val)
803 {
804  query_int32_t pdata = g_new0 (query_int32_def, 1);
805  pdata->pd.type_name = query_int32_type;
806  pdata->pd.how = how;
807  pdata->val = val;
808  return ((QofQueryPredData *) pdata);
809 }
810 
811 static char *
812 int32_to_string (gpointer object, QofParam * getter)
813 {
814  gint32 num =
815  ((query_int32_getter) getter->param_getfcn) (object, getter);
816 
817  return g_strdup_printf ("%d", num);
818 }
819 
820 /* ================================================================ */
821 /* QOF_TYPE_INT64 */
822 
823 static int
824 int64_match_predicate (gpointer object, QofParam * getter,
825  QofQueryPredData * pd)
826 {
827  gint64 val;
828  query_int64_t pdata = (query_int64_t) pd;
829 
830  VERIFY_PREDICATE (query_int64_type);
831 
832  val = ((query_int64_getter) getter->param_getfcn) (object, getter);
833 
834  switch (pd->how)
835  {
836  case QOF_COMPARE_LT:
837  return (val < pdata->val);
838  case QOF_COMPARE_LTE:
839  return (val <= pdata->val);
840  case QOF_COMPARE_EQUAL:
841  return (val == pdata->val);
842  case QOF_COMPARE_GT:
843  return (val > pdata->val);
844  case QOF_COMPARE_GTE:
845  return (val >= pdata->val);
846  case QOF_COMPARE_NEQ:
847  return (val != pdata->val);
848  default:
849  PWARN ("bad match type: %d", pd->how);
850  return 0;
851  }
852 }
853 
854 static int
855 int64_compare_func (gpointer a, gpointer b,
856  gint options __attribute__ ((unused)), QofParam * getter)
857 {
858  gint64 v1, v2;
859  g_return_val_if_fail (a && b && getter
860  && getter->param_getfcn, COMPARE_ERROR);
861 
862  v1 = ((query_int64_getter) getter->param_getfcn) (a, getter);
863  v2 = ((query_int64_getter) getter->param_getfcn) (b, getter);
864 
865  if (v1 < v2)
866  return -1;
867  if (v1 > v2)
868  return 1;
869  return 0;
870 }
871 
872 static void
873 int64_free_pdata (QofQueryPredData * pd)
874 {
875  query_int64_t pdata = (query_int64_t) pd;
876  VERIFY_PDATA (query_int64_type);
877  g_free (pdata);
878 }
879 
880 static QofQueryPredData *
881 int64_copy_predicate (QofQueryPredData * pd)
882 {
883  query_int64_t pdata = (query_int64_t) pd;
884  VERIFY_PDATA_R (query_int64_type);
885  return qof_query_int64_predicate (pd->how, pdata->val);
886 }
887 
888 static gboolean
889 int64_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
890 {
891  query_int64_t pd1 = (query_int64_t) p1;
892  query_int64_t pd2 = (query_int64_t) p2;
893 
894  return (pd1->val == pd2->val);
895 }
896 
898 qof_query_int64_predicate (QofQueryCompare how, gint64 val)
899 {
900  query_int64_t pdata = g_new0 (query_int64_def, 1);
901  pdata->pd.type_name = query_int64_type;
902  pdata->pd.how = how;
903  pdata->val = val;
904  return ((QofQueryPredData *) pdata);
905 }
906 
907 static char *
908 int64_to_string (gpointer object, QofParam * getter)
909 {
910  gint64 num =
911  ((query_int64_getter) getter->param_getfcn) (object, getter);
912 
913  return g_strdup_printf ("%" G_GINT64_FORMAT, num);
914 }
915 
916 /* ================================================================ */
917 /* QOF_TYPE_DOUBLE */
918 
919 static int
920 double_match_predicate (gpointer object, QofParam * getter,
921  QofQueryPredData * pd)
922 {
923  double val;
924  query_double_t pdata = (query_double_t) pd;
925 
926  VERIFY_PREDICATE (query_double_type);
927 
928  val = ((query_double_getter) getter->param_getfcn) (object, getter);
929 
930  switch (pd->how)
931  {
932  case QOF_COMPARE_LT:
933  return (val < pdata->val);
934  case QOF_COMPARE_LTE:
935  return (val <= pdata->val);
936  case QOF_COMPARE_EQUAL:
937  return (val == pdata->val);
938  case QOF_COMPARE_GT:
939  return (val > pdata->val);
940  case QOF_COMPARE_GTE:
941  return (val >= pdata->val);
942  case QOF_COMPARE_NEQ:
943  return (val != pdata->val);
944  default:
945  PWARN ("bad match type: %d", pd->how);
946  return 0;
947  }
948 }
949 
950 static int
951 double_compare_func (gpointer a, gpointer b,
952  gint options __attribute__ ((unused)), QofParam * getter)
953 {
954  double v1, v2;
955  g_return_val_if_fail (a && b && getter
956  && getter->param_getfcn, COMPARE_ERROR);
957 
958  v1 = ((query_double_getter) getter->param_getfcn) (a, getter);
959  v2 = ((query_double_getter) getter->param_getfcn) (b, getter);
960 
961  if (v1 < v2)
962  return -1;
963  if (v1 > v2)
964  return 1;
965  return 0;
966 }
967 
968 static void
969 double_free_pdata (QofQueryPredData * pd)
970 {
971  query_double_t pdata = (query_double_t) pd;
972  VERIFY_PDATA (query_double_type);
973  g_free (pdata);
974 }
975 
976 static QofQueryPredData *
977 double_copy_predicate (QofQueryPredData * pd)
978 {
979  query_double_t pdata = (query_double_t) pd;
980  VERIFY_PDATA_R (query_double_type);
981  return qof_query_double_predicate (pd->how, pdata->val);
982 }
983 
984 static gboolean
985 double_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
986 {
987  query_double_t pd1 = (query_double_t) p1;
988  query_double_t pd2 = (query_double_t) p2;
989 
990  return (pd1->val == pd2->val);
991 }
992 
994 qof_query_double_predicate (QofQueryCompare how, double val)
995 {
996  query_double_t pdata = g_new0 (query_double_def, 1);
997  pdata->pd.type_name = query_double_type;
998  pdata->pd.how = how;
999  pdata->val = val;
1000  return ((QofQueryPredData *) pdata);
1001 }
1002 
1003 static char *
1004 double_to_string (gpointer object, QofParam * getter)
1005 {
1006  double num =
1007  ((query_double_getter) getter->param_getfcn) (object, getter);
1008 
1009  return g_strdup_printf ("%f", num);
1010 }
1011 
1012 /* QOF_TYPE_BOOLEAN =================================================== */
1013 
1014 static int
1015 boolean_match_predicate (gpointer object, QofParam * getter,
1016  QofQueryPredData * pd)
1017 {
1018  gboolean val;
1019  query_boolean_t pdata = (query_boolean_t) pd;
1020 
1021  VERIFY_PREDICATE (query_boolean_type);
1022 
1023  val = ((query_boolean_getter) getter->param_getfcn) (object, getter);
1024 
1025  switch (pd->how)
1026  {
1027  case QOF_COMPARE_EQUAL:
1028  return (val == pdata->val);
1029  case QOF_COMPARE_NEQ:
1030  return (val != pdata->val);
1031  default:
1032  PWARN ("bad match type: %d", pd->how);
1033  return 0;
1034  }
1035 }
1036 
1037 static int
1038 boolean_compare_func (gpointer a, gpointer b,
1039  gint options __attribute__ ((unused)), QofParam * getter)
1040 {
1041  gboolean va, vb;
1042  g_return_val_if_fail (a && b && getter
1043  && getter->param_getfcn, COMPARE_ERROR);
1044  va = ((query_boolean_getter) getter->param_getfcn) (a, getter);
1045  vb = ((query_boolean_getter) getter->param_getfcn) (b, getter);
1046  if (!va && vb)
1047  return -1;
1048  if (va && !vb)
1049  return 1;
1050  return 0;
1051 }
1052 
1053 static void
1054 boolean_free_pdata (QofQueryPredData * pd)
1055 {
1056  query_boolean_t pdata = (query_boolean_t) pd;
1057  VERIFY_PDATA (query_boolean_type);
1058  g_free (pdata);
1059 }
1060 
1061 static QofQueryPredData *
1062 boolean_copy_predicate (QofQueryPredData * pd)
1063 {
1064  query_boolean_t pdata = (query_boolean_t) pd;
1065  VERIFY_PDATA_R (query_boolean_type);
1066  return qof_query_boolean_predicate (pd->how, pdata->val);
1067 }
1068 
1069 static gboolean
1070 boolean_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1071 {
1072  query_boolean_t pd1 = (query_boolean_t) p1;
1073  query_boolean_t pd2 = (query_boolean_t) p2;
1074 
1075  return (pd1->val == pd2->val);
1076 }
1077 
1079 qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
1080 {
1081  query_boolean_t pdata;
1082  g_return_val_if_fail (how == QOF_COMPARE_EQUAL
1083  || how == QOF_COMPARE_NEQ, NULL);
1084 
1085  pdata = g_new0 (query_boolean_def, 1);
1086  pdata->pd.type_name = query_boolean_type;
1087  pdata->pd.how = how;
1088  pdata->val = val;
1089  return ((QofQueryPredData *) pdata);
1090 }
1091 
1092 static char *
1093 boolean_to_string (gpointer object, QofParam * getter)
1094 {
1095  gboolean num =
1096  ((query_boolean_getter) getter->param_getfcn) (object, getter);
1097 
1098  return g_strdup_printf ("%s", (num ? "X" : ""));
1099 }
1100 
1101 /* QOF_TYPE_CHAR =================================================== */
1102 
1103 static int
1104 char_match_predicate (gpointer object, QofParam * getter,
1105  QofQueryPredData * pd)
1106 {
1107  char c;
1108  query_char_t pdata = (query_char_t) pd;
1109 
1110  VERIFY_PREDICATE (query_char_type);
1111 
1112  c = ((query_char_getter) getter->param_getfcn) (object, getter);
1113 
1114  switch (pdata->options)
1115  {
1116  case QOF_CHAR_MATCH_ANY:
1117  if (strchr (pdata->char_list, c))
1118  return 1;
1119  return 0;
1120  case QOF_CHAR_MATCH_NONE:
1121  if (!strchr (pdata->char_list, c))
1122  return 1;
1123  return 0;
1124  default:
1125  PWARN ("bad match type");
1126  return 0;
1127  }
1128 }
1129 
1130 static int
1131 char_compare_func (gpointer a, gpointer b,
1132  gint options __attribute__ ((unused)), QofParam * getter)
1133 {
1134  char va, vb;
1135  g_return_val_if_fail (a && b && getter
1136  && getter->param_getfcn, COMPARE_ERROR);
1137  va = ((query_char_getter) getter->param_getfcn) (a, getter);
1138  vb = ((query_char_getter) getter->param_getfcn) (b, getter);
1139  return (va - vb);
1140 }
1141 
1142 static void
1143 char_free_pdata (QofQueryPredData * pd)
1144 {
1145  query_char_t pdata = (query_char_t) pd;
1146  VERIFY_PDATA (query_char_type);
1147  g_free (pdata->char_list);
1148  g_free (pdata);
1149 }
1150 
1151 static QofQueryPredData *
1152 char_copy_predicate (QofQueryPredData * pd)
1153 {
1154  query_char_t pdata = (query_char_t) pd;
1155  VERIFY_PDATA_R (query_char_type);
1156  return qof_query_char_predicate (pdata->options, pdata->char_list);
1157 }
1158 
1159 static gboolean
1160 char_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1161 {
1162  query_char_t pd1 = (query_char_t) p1;
1163  query_char_t pd2 = (query_char_t) p2;
1164 
1165  if (pd1->options != pd2->options)
1166  return FALSE;
1167  return (safe_strcmp (pd1->char_list, pd2->char_list) == 0);
1168 }
1169 
1171 qof_query_char_predicate (QofCharMatch options, const char *chars)
1172 {
1173  query_char_t pdata;
1174  g_return_val_if_fail (chars, NULL);
1175  pdata = g_new0 (query_char_def, 1);
1176  pdata->pd.type_name = query_char_type;
1177  pdata->pd.how = QOF_COMPARE_EQUAL;
1178  pdata->options = options;
1179  pdata->char_list = g_strdup (chars);
1180  return ((QofQueryPredData *) pdata);
1181 }
1182 
1183 static char *
1184 char_to_string (gpointer object, QofParam * getter)
1185 {
1186  char num = ((query_char_getter) getter->param_getfcn) (object, getter);
1187 
1188  return g_strdup_printf ("%c", num);
1189 }
1190 
1191 /* QOF_TYPE_KVP ================================================ */
1192 
1193 static int
1194 kvp_match_predicate (gpointer object, QofParam * getter,
1195  QofQueryPredData * pd)
1196 {
1197  int compare;
1198  KvpFrame *kvp;
1199  KvpValue *value;
1200  query_kvp_t pdata = (query_kvp_t) pd;
1201 
1202  VERIFY_PREDICATE (query_kvp_type);
1203 
1204  kvp = ((query_kvp_getter) getter->param_getfcn) (object, getter);
1205  if (!kvp)
1206  return 0;
1207 
1208  value = kvp_frame_get_slot_path_gslist (kvp, pdata->path);
1209  if (!value)
1210  return 0;
1211 
1212  if (kvp_value_get_type (value) != kvp_value_get_type (pdata->value))
1213  return 0;
1214 
1215  compare = kvp_value_compare (value, pdata->value);
1216 
1217  switch (pd->how)
1218  {
1219  case QOF_COMPARE_LT:
1220  return (compare < 0);
1221  case QOF_COMPARE_LTE:
1222  return (compare <= 0);
1223  case QOF_COMPARE_EQUAL:
1224  return (compare == 0);
1225  case QOF_COMPARE_GTE:
1226  return (compare >= 0);
1227  case QOF_COMPARE_GT:
1228  return (compare > 0);
1229  case QOF_COMPARE_NEQ:
1230  return (compare != 0);
1231  default:
1232  PWARN ("bad match type: %d", pd->how);
1233  return 0;
1234  }
1235 }
1236 
1237 static void
1238 kvp_free_pdata (QofQueryPredData * pd)
1239 {
1240  query_kvp_t pdata = (query_kvp_t) pd;
1241  GSList *node;
1242 
1243  VERIFY_PDATA (query_kvp_type);
1244  kvp_value_delete (pdata->value);
1245  for (node = pdata->path; node; node = node->next)
1246  {
1247  g_free (node->data);
1248  node->data = NULL;
1249  }
1250  g_slist_free (pdata->path);
1251  g_free (pdata);
1252 }
1253 
1254 static QofQueryPredData *
1255 kvp_copy_predicate (QofQueryPredData * pd)
1256 {
1257  query_kvp_t pdata = (query_kvp_t) pd;
1258  VERIFY_PDATA_R (query_kvp_type);
1259  return qof_query_kvp_predicate (pd->how, pdata->path, pdata->value);
1260 }
1261 
1262 static gboolean
1263 kvp_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1264 {
1265  query_kvp_t pd1 = (query_kvp_t) p1;
1266  query_kvp_t pd2 = (query_kvp_t) p2;
1267  GSList *n1, *n2;
1268 
1269  n1 = pd1->path;
1270  n2 = pd2->path;
1271 
1272  for (; n1 && n2; n1 = n1->next, n2 = n2->next)
1273  {
1274  if (safe_strcmp (n1->data, n2->data) != 0)
1275  return FALSE;
1276  }
1277 
1278  if (n1 || n2)
1279  return FALSE;
1280 
1281  return (kvp_value_compare (pd1->value, pd2->value) == 0);
1282 }
1283 
1286  GSList * path, const KvpValue * value)
1287 {
1288  query_kvp_t pdata;
1289  GSList *node;
1290 
1291  g_return_val_if_fail (path && value, NULL);
1292 
1293  pdata = g_new0 (query_kvp_def, 1);
1294  pdata->pd.type_name = query_kvp_type;
1295  pdata->pd.how = how;
1296  pdata->value = kvp_value_copy (value);
1297  pdata->path = g_slist_copy (path);
1298  for (node = pdata->path; node; node = node->next)
1299  node->data = g_strdup (node->data);
1300 
1301  return ((QofQueryPredData *) pdata);
1302 }
1303 
1306  const char *path, const KvpValue * value)
1307 {
1308  QofQueryPredData *pd;
1309  GSList *spath = NULL;
1310  char *str, *p;
1311 
1312  if (!path)
1313  return NULL;
1314 
1315  str = g_strdup (path);
1316  p = str;
1317  if (0 == *p)
1318  return NULL;
1319  if ('/' == *p)
1320  p++;
1321 
1322  while (p)
1323  {
1324  spath = g_slist_append (spath, p);
1325  p = strchr (p, '/');
1326  if (p)
1327  {
1328  *p = 0;
1329  p++;
1330  }
1331  }
1332 
1333  pd = qof_query_kvp_predicate (how, spath, value);
1334  g_free (str);
1335  return pd;
1336 }
1337 
1338 
1339 /* QOF_TYPE_COLLECT =============================================== */
1340 
1341 static int
1342 collect_match_predicate (gpointer object, QofParam * getter,
1343  QofQueryPredData * pd)
1344 {
1345  query_coll_t pdata;
1346  QofCollection *coll;
1347  GList *node, *node2, *o_list;
1348  const GUID *guid;
1349 
1350  pdata = (query_coll_t) pd;
1351  VERIFY_PREDICATE (query_collect_type);
1352  coll = ((query_collect_getter) getter->param_getfcn) (object, getter);
1353  guid = NULL;
1354  switch (pdata->options)
1355  {
1356  case QOF_GUID_MATCH_ALL:
1357  {
1358  for (node = pdata->guids; node; node = node->next)
1359  {
1360  for (o_list = object; o_list; o_list = o_list->next)
1361  {
1362  guid = ((query_guid_getter) getter->param_getfcn)
1363  (o_list->data, getter);
1364  if (guid_equal (node->data, guid))
1365  {
1366  break;
1367  }
1368  }
1369  if (o_list == NULL)
1370  {
1371  break;
1372  }
1373  }
1374  break;
1375  }
1377  {
1378  o_list =
1379  ((query_glist_getter) getter->param_getfcn) (object,
1380  getter);
1381  for (node = o_list; node; node = node->next)
1382  {
1383  for (node2 = pdata->guids; node2; node2 = node2->next)
1384  {
1385  if (guid_equal (node->data, node2->data))
1386  {
1387  break;
1388  }
1389  }
1390  if (node2 != NULL)
1391  {
1392  break;
1393  }
1394  }
1395  g_list_free (o_list);
1396  break;
1397  }
1398  default:
1399  {
1400  guid =
1401  ((query_guid_getter) getter->param_getfcn) (object,
1402  getter);
1403  for (node = pdata->guids; node; node = node->next)
1404  {
1405  if (guid_equal (node->data, guid))
1406  {
1407  break;
1408  }
1409  }
1410  }
1411  switch (pdata->options)
1412  {
1413  case QOF_GUID_MATCH_ANY:
1415  {
1416  return (node != NULL);
1417  break;
1418  }
1419  case QOF_GUID_MATCH_NONE:
1420  case QOF_GUID_MATCH_ALL:
1421  {
1422  return (node == NULL);
1423  break;
1424  }
1425  case QOF_GUID_MATCH_NULL:
1426  {
1427  return (guid == NULL);
1428  break;
1429  }
1430  default:
1431  {
1432  PWARN ("bad match type");
1433  return 0;
1434  }
1435  }
1436  }
1437  return 0;
1438 }
1439 
1440 static int
1441 collect_compare_func (gpointer a, gpointer b,
1442  gint options __attribute__ ((unused)),
1443  QofParam * getter)
1444 {
1445  gint result;
1446  QofCollection *c1, *c2;
1447 
1448  c1 = ((query_collect_getter) getter->param_getfcn) (a, getter);
1449  c2 = ((query_collect_getter) getter->param_getfcn) (b, getter);
1450  result = qof_collection_compare (c1, c2);
1451  return result;
1452 }
1453 
1454 static void
1455 collect_free_pdata (QofQueryPredData * pd)
1456 {
1457  query_coll_t pdata;
1458  GList *node;
1459 
1460  node = NULL;
1461  pdata = (query_coll_t) pd;
1462  VERIFY_PDATA (query_collect_type);
1463  for (node = pdata->guids; node; node = node->next)
1464  {
1465  guid_free (node->data);
1466  }
1467  qof_collection_destroy (pdata->coll);
1468  g_list_free (pdata->guids);
1469  g_free (pdata);
1470 }
1471 
1472 static QofQueryPredData *
1473 collect_copy_predicate (QofQueryPredData * pd)
1474 {
1475  query_coll_t pdata = (query_coll_t) pd;
1476 
1477  VERIFY_PDATA_R (query_collect_type);
1478  return qof_query_collect_predicate (pdata->options, pdata->coll);
1479 }
1480 
1481 static gboolean
1482 collect_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1483 {
1484  query_coll_t pd1;
1485  query_coll_t pd2;
1486  gint result;
1487 
1488  pd1 = (query_coll_t) p1;
1489  pd2 = (query_coll_t) p2;
1490  result = qof_collection_compare (pd1->coll, pd2->coll);
1491  if (result == 0)
1492  {
1493  return TRUE;
1494  }
1495  return FALSE;
1496 }
1497 
1498 static void
1499 query_collect_cb (QofEntity * ent, gpointer user_data)
1500 {
1501  query_coll_t pdata;
1502  GUID *guid;
1503 
1504  guid = guid_malloc ();
1505  guid = (GUID *) qof_entity_get_guid (ent);
1506  pdata = (query_coll_t) user_data;
1507  pdata->guids = g_list_append (pdata->guids, guid);
1508 }
1509 
1511 qof_query_collect_predicate (QofGuidMatch options, QofCollection * coll)
1512 {
1513  query_coll_t pdata;
1514 
1515  g_return_val_if_fail (coll, NULL);
1516  pdata = g_new0 (query_coll_def, 1);
1517  pdata->pd.type_name = query_collect_type;
1518  pdata->options = options;
1519  qof_collection_foreach (coll, query_collect_cb, pdata);
1520  if (NULL == pdata->guids)
1521  {
1522  return NULL;
1523  }
1524  return ((QofQueryPredData *) pdata);
1525 }
1526 
1527 /* QOF_TYPE_CHOICE */
1528 
1529 static int
1530 choice_match_predicate (gpointer object, QofParam * getter,
1531  QofQueryPredData * pd)
1532 {
1533  query_choice_t pdata = (query_choice_t) pd;
1534  GList *node, *o_list;
1535  const GUID *guid = NULL;
1536 
1537  VERIFY_PREDICATE (query_choice_type);
1538 
1539  switch (pdata->options)
1540  {
1541 
1542  case QOF_GUID_MATCH_ALL:
1543  /* object is a GList of objects; param_getfcn must be called on each one.
1544  * See if every guid in the predicate is accounted-for in the
1545  * object list
1546  */
1547 
1548  for (node = pdata->guids; node; node = node->next)
1549  {
1550  /* See if this GUID matches the object's guid */
1551  for (o_list = object; o_list; o_list = o_list->next)
1552  {
1553  guid =
1554  ((query_choice_getter) getter->param_getfcn) (o_list->
1555  data, getter);
1556  if (guid_equal (node->data, guid))
1557  break;
1558  }
1559 
1560  /*
1561  * If o_list is NULL, we've walked the whole list without finding
1562  * a match. Therefore break out now, the match has failed.
1563  */
1564  if (o_list == NULL)
1565  break;
1566  }
1567 
1568  /*
1569  * The match is complete. If node == NULL then we've succesfully
1570  * found a match for all the guids in the predicate. Return
1571  * appropriately below.
1572  */
1573 
1574  break;
1575 
1577 
1578  o_list =
1579  ((query_glist_getter) getter->param_getfcn) (object, getter);
1580 
1581  for (node = o_list; node; node = node->next)
1582  {
1583  GList *node2;
1584 
1585  for (node2 = pdata->guids; node2; node2 = node2->next)
1586  {
1587  if (guid_equal (node->data, node2->data))
1588  break;
1589  }
1590 
1591  if (node2 != NULL)
1592  break;
1593  }
1594 
1595  g_list_free (o_list);
1596 
1597  break;
1598 
1599  default:
1600  /* object is a single object, getter returns a GUID*
1601  *
1602  * See if the guid is in the list
1603  */
1604 
1605  guid =
1606  ((query_choice_getter) getter->param_getfcn) (object, getter);
1607  for (node = pdata->guids; node; node = node->next)
1608  {
1609  if (guid_equal (node->data, guid))
1610  break;
1611  }
1612  }
1613 
1614  switch (pdata->options)
1615  {
1616  case QOF_GUID_MATCH_ANY:
1618  return (node != NULL);
1619  break;
1620  case QOF_GUID_MATCH_NONE:
1621  case QOF_GUID_MATCH_ALL:
1622  return (node == NULL);
1623  break;
1624  case QOF_GUID_MATCH_NULL:
1625  return (guid == NULL);
1626  break;
1627  default:
1628  PWARN ("bad match type");
1629  return 0;
1630  }
1631 }
1632 
1633 static void
1634 choice_free_pdata (QofQueryPredData * pd)
1635 {
1636  query_choice_t pdata = (query_choice_t) pd;
1637  GList *node;
1638  VERIFY_PDATA (query_choice_type);
1639  for (node = pdata->guids; node; node = node->next)
1640  {
1641  guid_free (node->data);
1642  }
1643  g_list_free (pdata->guids);
1644  g_free (pdata);
1645 }
1646 
1647 static QofQueryPredData *
1648 choice_copy_predicate (QofQueryPredData * pd)
1649 {
1650  query_choice_t pdata = (query_choice_t) pd;
1651  VERIFY_PDATA_R (query_choice_type);
1652  return qof_query_choice_predicate (pdata->options, pdata->guids);
1653 }
1654 
1655 static gboolean
1656 choice_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1657 {
1658  query_choice_t pd1 = (query_choice_t) p1;
1659  query_choice_t pd2 = (query_choice_t) p2;
1660  GList *l1 = pd1->guids, *l2 = pd2->guids;
1661 
1662  if (pd1->options != pd2->options)
1663  return FALSE;
1664  if (g_list_length (l1) != g_list_length (l2))
1665  return FALSE;
1666  for (; l1; l1 = l1->next, l2 = l2->next)
1667  {
1668  if (!guid_equal (l1->data, l2->data))
1669  return FALSE;
1670  }
1671  return TRUE;
1672 }
1673 
1675 qof_query_choice_predicate (QofGuidMatch options, GList * guid_list)
1676 {
1677  query_choice_t pdata;
1678  GList *node;
1679 
1680  if (NULL == guid_list)
1681  return NULL;
1682 
1683  pdata = g_new0 (query_choice_def, 1);
1684  pdata->pd.how = QOF_COMPARE_EQUAL;
1685  pdata->pd.type_name = query_choice_type;
1686  pdata->options = options;
1687 
1688  pdata->guids = g_list_copy (guid_list);
1689  for (node = pdata->guids; node; node = node->next)
1690  {
1691  GUID *guid = guid_malloc ();
1692  *guid = *((GUID *) node->data);
1693  node->data = guid;
1694  }
1695  return ((QofQueryPredData *) pdata);
1696 }
1697 
1698 
1699 /* initialization ================================================== */
1711 static void
1712 qof_query_register_core_object (QofType core_name,
1713  QofQueryPredicateFunc pred,
1714  QofCompareFunc comp,
1715  QueryPredicateCopyFunc copy,
1716  QueryPredDataFree pd_free,
1717  QueryToString toString, QueryPredicateEqual pred_equal)
1718 {
1719  g_return_if_fail (core_name);
1720  g_return_if_fail (*core_name != '\0');
1721 
1722  if (pred)
1723  g_hash_table_insert (predTable, (char *) core_name, pred);
1724 
1725  if (comp)
1726  g_hash_table_insert (cmpTable, (char *) core_name, comp);
1727 
1728  if (copy)
1729  g_hash_table_insert (copyTable, (char *) core_name, copy);
1730 
1731  if (pd_free)
1732  g_hash_table_insert (freeTable, (char *) core_name, pd_free);
1733 
1734  if (toString)
1735  g_hash_table_insert (toStringTable, (char *) core_name, toString);
1736 
1737  if (pred_equal)
1738  g_hash_table_insert (predEqualTable, (char *) core_name,
1739  pred_equal);
1740 }
1741 
1742 /* Deprecated */
1743 #ifndef QOF_DISABLE_DEPRECATED
1744 /* QOF_TYPE_DATE =================================================== */
1745 typedef Timespec (*query_date_getter) (gpointer, QofParam *);
1746 static const gchar *query_date_type = QOF_TYPE_DATE;
1747 
1748 static gint
1749 date_compare (Timespec ta, Timespec tb, QofDateMatch options)
1750 {
1751 
1752  if (options == QOF_DATE_MATCH_DAY)
1753  {
1754  ta = timespecCanonicalDayTime (ta);
1755  tb = timespecCanonicalDayTime (tb);
1756  }
1757 
1758  if (ta.tv_sec < tb.tv_sec)
1759  return -1;
1760  if (ta.tv_sec > tb.tv_sec)
1761  return 1;
1762 
1763  if (ta.tv_nsec < tb.tv_nsec)
1764  return -1;
1765  if (ta.tv_nsec > tb.tv_nsec)
1766  return 1;
1767 
1768  return 0;
1769 }
1770 
1771 static int
1772 date_match_predicate (gpointer object, QofParam *getter,
1773  QofQueryPredData *pd)
1774 {
1775  query_date_t pdata = (query_date_t)pd;
1776  Timespec objtime;
1777  int compare;
1778 
1779  VERIFY_PREDICATE (query_date_type);
1780 
1781  objtime = ((query_date_getter)getter->param_getfcn) (object, getter);
1782  compare = date_compare (objtime, pdata->date, pdata->options);
1783 
1784  switch (pd->how) {
1785  case QOF_COMPARE_LT:
1786  return (compare < 0);
1787  case QOF_COMPARE_LTE:
1788  return (compare <= 0);
1789  case QOF_COMPARE_EQUAL:
1790  return (compare == 0);
1791  case QOF_COMPARE_GT:
1792  return (compare > 0);
1793  case QOF_COMPARE_GTE:
1794  return (compare >= 0);
1795  case QOF_COMPARE_NEQ:
1796  return (compare != 0);
1797  default:
1798  PWARN ("bad match type: %d", pd->how);
1799  return 0;
1800  }
1801 }
1802 
1803 static gint
1804 date_compare_func (gpointer a, gpointer b, gint options, QofParam * getter)
1805 {
1806  Timespec ta, tb;
1807 
1808  g_return_val_if_fail (a && b && getter
1809  && getter->param_getfcn, COMPARE_ERROR);
1810 
1811  ta = ((query_date_getter) getter->param_getfcn) (a, getter);
1812  tb = ((query_date_getter) getter->param_getfcn) (b, getter);
1813 
1814  return date_compare (ta, tb, options);
1815 }
1816 
1817 static void
1818 date_free_pdata (QofQueryPredData * pd)
1819 {
1820  query_date_t pdata = (query_date_t) pd;
1821 
1822  VERIFY_PDATA (query_date_type);
1823 
1824  g_free (pdata);
1825 }
1826 
1827 static QofQueryPredData *
1828 date_copy_predicate (QofQueryPredData *pd)
1829 {
1830  query_date_t pdata = (query_date_t)pd;
1831 
1832  VERIFY_PDATA_R (query_date_type);
1833 
1834  return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
1835 }
1836 
1837 static gboolean
1838 date_predicate_equal (QofQueryPredData *p1, QofQueryPredData *p2)
1839 {
1840  query_date_t pd1 = (query_date_t) p1;
1841  query_date_t pd2 = (query_date_t) p2;
1842 
1843  if (pd1->options != pd2->options) return FALSE;
1844  return timespec_equal (&(pd1->date), &(pd2->date));
1845 }
1846 
1849  QofDateMatch options, Timespec date)
1850 {
1851  query_date_t pdata;
1852 
1853  pdata = g_new0 (query_date_def, 1);
1854  pdata->pd.type_name = query_date_type;
1855  pdata->pd.how = how;
1856  pdata->options = options;
1857  pdata->date = date;
1858  return ((QofQueryPredData*)pdata);
1859 }
1860 
1861 gboolean
1863 {
1864  query_date_t pdata = (query_date_t)pd;
1865 
1866  if (pdata->pd.type_name != query_date_type)
1867  return FALSE;
1868  *date = pdata->date;
1869  return TRUE;
1870 }
1871 
1872 static gchar *
1873 date_to_string (gpointer object, QofParam * getter)
1874 {
1875  Timespec ts =
1876  ((query_date_getter) getter->param_getfcn) (object, getter);
1877 
1878  if (ts.tv_sec || ts.tv_nsec)
1879  return g_strdup (gnc_print_date (ts));
1880 
1881  return NULL;
1882 }
1883 
1884 #endif // QOF_DISABLE_DEPRECATED QOF_TYPE_DATE
1885 
1886 static void
1887 init_tables (void)
1888 {
1889  guint i;
1890  struct
1891  {
1892  QofType name;
1893  QofQueryPredicateFunc pred;
1894  QofCompareFunc comp;
1895  QueryPredicateCopyFunc copy;
1896  QueryPredDataFree pd_free;
1897  QueryToString toString;
1898  QueryPredicateEqual pred_equal;
1899  } knownTypes[] =
1900  {
1901  {
1902  QOF_TYPE_STRING, string_match_predicate, string_compare_func,
1903  string_copy_predicate, string_free_pdata,
1904  string_to_string, string_predicate_equal},
1905 #ifndef QOF_DISABLE_DEPRECATED
1906  {
1907  QOF_TYPE_DATE, date_match_predicate, date_compare_func,
1908  date_copy_predicate, date_free_pdata, date_to_string,
1909  date_predicate_equal},
1910 #endif
1911  {
1912  QOF_TYPE_TIME, time_match_predicate, time_compare_func,
1913  time_copy_predicate, time_free_pdata, time_to_string,
1914  time_predicate_equal},
1915  {
1916  QOF_TYPE_DEBCRED, numeric_match_predicate,
1917  numeric_compare_func, numeric_copy_predicate,
1918  numeric_free_pdata, debcred_to_string,
1919  numeric_predicate_equal},
1920  {
1921  QOF_TYPE_NUMERIC, numeric_match_predicate,
1922  numeric_compare_func, numeric_copy_predicate,
1923  numeric_free_pdata, numeric_to_string,
1924  numeric_predicate_equal},
1925  {
1926  QOF_TYPE_GUID, guid_match_predicate, NULL,
1927  guid_copy_predicate, guid_free_pdata, NULL,
1928  guid_predicate_equal},
1929  {
1930  QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
1931  int32_copy_predicate, int32_free_pdata,
1932  int32_to_string, int32_predicate_equal},
1933  {
1934  QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
1935  int64_copy_predicate, int64_free_pdata,
1936  int64_to_string, int64_predicate_equal},
1937  {
1938  QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
1939  double_copy_predicate, double_free_pdata,
1940  double_to_string, double_predicate_equal},
1941  {
1942  QOF_TYPE_BOOLEAN, boolean_match_predicate,
1943  boolean_compare_func, boolean_copy_predicate,
1944  boolean_free_pdata, boolean_to_string,
1945  boolean_predicate_equal},
1946  {
1947  QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
1948  char_copy_predicate, char_free_pdata, char_to_string,
1949  char_predicate_equal},
1950  {
1951  QOF_TYPE_KVP, kvp_match_predicate, NULL, kvp_copy_predicate,
1952  kvp_free_pdata, NULL, kvp_predicate_equal},
1953  {
1954  QOF_TYPE_COLLECT, collect_match_predicate,
1955  collect_compare_func, collect_copy_predicate,
1956  collect_free_pdata, NULL, collect_predicate_equal},
1957  {
1958  QOF_TYPE_CHOICE, choice_match_predicate, NULL,
1959  choice_copy_predicate, choice_free_pdata, NULL,
1960  choice_predicate_equal},};
1961 
1962  /* Register the known data types */
1963  for (i = 0; i < (sizeof (knownTypes) / sizeof (*knownTypes)); i++)
1964  {
1965  qof_query_register_core_object (knownTypes[i].name,
1966  knownTypes[i].pred,
1967  knownTypes[i].comp,
1968  knownTypes[i].copy,
1969  knownTypes[i].pd_free,
1970  knownTypes[i].toString, knownTypes[i].pred_equal);
1971  }
1972 }
1973 
1974 static QueryPredicateCopyFunc
1975 qof_query_copy_predicate (QofType type)
1976 {
1977  QueryPredicateCopyFunc rc;
1978  g_return_val_if_fail (type, NULL);
1979  rc = g_hash_table_lookup (copyTable, type);
1980  return rc;
1981 }
1982 
1983 static QueryPredDataFree
1984 qof_query_predicate_free (QofType type)
1985 {
1986  g_return_val_if_fail (type, NULL);
1987  return g_hash_table_lookup (freeTable, type);
1988 }
1989 
1990 /********************************************************************/
1991 /* PUBLISHED API FUNCTIONS */
1992 
1993 void
1994 qof_query_core_init (void)
1995 {
1996  /* Only let us initialize once */
1997  if (initialized)
1998  return;
1999  initialized = TRUE;
2000 
2001  /* Create the tables */
2002  predTable = g_hash_table_new (g_str_hash, g_str_equal);
2003  cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
2004  copyTable = g_hash_table_new (g_str_hash, g_str_equal);
2005  freeTable = g_hash_table_new (g_str_hash, g_str_equal);
2006  toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
2007  predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
2008 
2009  init_tables ();
2010 }
2011 
2012 void
2013 qof_query_core_shutdown (void)
2014 {
2015  if (!initialized)
2016  return;
2017  initialized = FALSE;
2018 
2019  g_hash_table_destroy (predTable);
2020  g_hash_table_destroy (cmpTable);
2021  g_hash_table_destroy (copyTable);
2022  g_hash_table_destroy (freeTable);
2023  g_hash_table_destroy (toStringTable);
2024  g_hash_table_destroy (predEqualTable);
2025 }
2026 
2027 QofQueryPredicateFunc
2028 qof_query_core_get_predicate (QofType type)
2029 {
2030  g_return_val_if_fail (type, NULL);
2031  return g_hash_table_lookup (predTable, type);
2032 }
2033 
2034 QofCompareFunc
2035 qof_query_core_get_compare (QofType type)
2036 {
2037  g_return_val_if_fail (type, NULL);
2038  return g_hash_table_lookup (cmpTable, type);
2039 }
2040 
2041 void
2043 {
2044  QueryPredDataFree free_fcn;
2045 
2046  g_return_if_fail (pdata);
2047  g_return_if_fail (pdata->type_name);
2048 
2049  free_fcn = qof_query_predicate_free (pdata->type_name);
2050  free_fcn (pdata);
2051 }
2052 
2055 {
2056  QueryPredicateCopyFunc copy;
2057 
2058  g_return_val_if_fail (pdata, NULL);
2059  g_return_val_if_fail (pdata->type_name, NULL);
2060 
2061  copy = qof_query_copy_predicate (pdata->type_name);
2062  return (copy (pdata));
2063 }
2064 
2065 gchar *
2066 qof_query_core_to_string (QofType type, gpointer object,
2067  QofParam * getter)
2068 {
2069  QueryToString toString;
2070 
2071  g_return_val_if_fail (type, NULL);
2072  g_return_val_if_fail (object, NULL);
2073  g_return_val_if_fail (getter, NULL);
2074 
2075  toString = g_hash_table_lookup (toStringTable, type);
2076  g_return_val_if_fail (toString, NULL);
2077 
2078  return toString (object, getter);
2079 }
2080 
2081 gboolean
2082 qof_query_core_predicate_equal (QofQueryPredData * p1,
2083  QofQueryPredData * p2)
2084 {
2085  QueryPredicateEqual pred_equal;
2086 
2087  if (p1 == p2)
2088  return TRUE;
2089  if (!p1 || !p2)
2090  return FALSE;
2091 
2092  if (p1->how != p2->how)
2093  return FALSE;
2094  if (safe_strcmp (p1->type_name, p2->type_name))
2095  return FALSE;
2096 
2097  pred_equal = g_hash_table_lookup (predEqualTable, p1->type_name);
2098  g_return_val_if_fail (pred_equal, FALSE);
2099 
2100  return pred_equal (p1, p2);
2101 }