QOF  0.8.7
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-2008 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 * G_GNUC_UNUSED 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 static void
1743 init_tables (void)
1744 {
1745  guint i;
1746  struct
1747  {
1748  QofType name;
1749  QofQueryPredicateFunc pred;
1750  QofCompareFunc comp;
1751  QueryPredicateCopyFunc copy;
1752  QueryPredDataFree pd_free;
1753  QueryToString toString;
1754  QueryPredicateEqual pred_equal;
1755  } knownTypes[] =
1756  {
1757  {
1758  QOF_TYPE_STRING, string_match_predicate, string_compare_func,
1759  string_copy_predicate, string_free_pdata,
1760  string_to_string, string_predicate_equal},
1761  {
1762  QOF_TYPE_TIME, time_match_predicate, time_compare_func,
1763  time_copy_predicate, time_free_pdata, time_to_string,
1764  time_predicate_equal},
1765  {
1766  QOF_TYPE_DEBCRED, numeric_match_predicate,
1767  numeric_compare_func, numeric_copy_predicate,
1768  numeric_free_pdata, debcred_to_string,
1769  numeric_predicate_equal},
1770  {
1771  QOF_TYPE_NUMERIC, numeric_match_predicate,
1772  numeric_compare_func, numeric_copy_predicate,
1773  numeric_free_pdata, numeric_to_string,
1774  numeric_predicate_equal},
1775  {
1776  QOF_TYPE_GUID, guid_match_predicate, NULL,
1777  guid_copy_predicate, guid_free_pdata, NULL,
1778  guid_predicate_equal},
1779  {
1780  QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
1781  int32_copy_predicate, int32_free_pdata,
1782  int32_to_string, int32_predicate_equal},
1783  {
1784  QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
1785  int64_copy_predicate, int64_free_pdata,
1786  int64_to_string, int64_predicate_equal},
1787  {
1788  QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
1789  double_copy_predicate, double_free_pdata,
1790  double_to_string, double_predicate_equal},
1791  {
1792  QOF_TYPE_BOOLEAN, boolean_match_predicate,
1793  boolean_compare_func, boolean_copy_predicate,
1794  boolean_free_pdata, boolean_to_string,
1795  boolean_predicate_equal},
1796  {
1797  QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
1798  char_copy_predicate, char_free_pdata, char_to_string,
1799  char_predicate_equal},
1800  {
1801  QOF_TYPE_KVP, kvp_match_predicate, NULL, kvp_copy_predicate,
1802  kvp_free_pdata, NULL, kvp_predicate_equal},
1803  {
1804  QOF_TYPE_COLLECT, collect_match_predicate,
1805  collect_compare_func, collect_copy_predicate,
1806  collect_free_pdata, NULL, collect_predicate_equal},
1807  {
1808  QOF_TYPE_CHOICE, choice_match_predicate, NULL,
1809  choice_copy_predicate, choice_free_pdata, NULL,
1810  choice_predicate_equal},};
1811 
1812  /* Register the known data types */
1813  for (i = 0; i < (sizeof (knownTypes) / sizeof (*knownTypes)); i++)
1814  {
1815  qof_query_register_core_object (knownTypes[i].name,
1816  knownTypes[i].pred,
1817  knownTypes[i].comp,
1818  knownTypes[i].copy,
1819  knownTypes[i].pd_free,
1820  knownTypes[i].toString, knownTypes[i].pred_equal);
1821  }
1822 }
1823 
1824 static QueryPredicateCopyFunc
1825 qof_query_copy_predicate (QofType type)
1826 {
1827  QueryPredicateCopyFunc rc;
1828  g_return_val_if_fail (type, NULL);
1829  rc = g_hash_table_lookup (copyTable, type);
1830  return rc;
1831 }
1832 
1833 static QueryPredDataFree
1834 qof_query_predicate_free (QofType type)
1835 {
1836  g_return_val_if_fail (type, NULL);
1837  return g_hash_table_lookup (freeTable, type);
1838 }
1839 
1840 /********************************************************************/
1841 /* PUBLISHED API FUNCTIONS */
1842 
1843 void
1844 qof_query_core_init (void)
1845 {
1846  /* Only let us initialize once */
1847  if (initialized)
1848  return;
1849  initialized = TRUE;
1850 
1851  /* Create the tables */
1852  predTable = g_hash_table_new (g_str_hash, g_str_equal);
1853  cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
1854  copyTable = g_hash_table_new (g_str_hash, g_str_equal);
1855  freeTable = g_hash_table_new (g_str_hash, g_str_equal);
1856  toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
1857  predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
1858 
1859  init_tables ();
1860 }
1861 
1862 void
1863 qof_query_core_shutdown (void)
1864 {
1865  if (!initialized)
1866  return;
1867  initialized = FALSE;
1868 
1869  g_hash_table_destroy (predTable);
1870  g_hash_table_destroy (cmpTable);
1871  g_hash_table_destroy (copyTable);
1872  g_hash_table_destroy (freeTable);
1873  g_hash_table_destroy (toStringTable);
1874  g_hash_table_destroy (predEqualTable);
1875 }
1876 
1877 QofQueryPredicateFunc
1878 qof_query_core_get_predicate (QofType type)
1879 {
1880  g_return_val_if_fail (type, NULL);
1881  return g_hash_table_lookup (predTable, type);
1882 }
1883 
1884 QofCompareFunc
1885 qof_query_core_get_compare (QofType type)
1886 {
1887  g_return_val_if_fail (type, NULL);
1888  return g_hash_table_lookup (cmpTable, type);
1889 }
1890 
1891 void
1893 {
1894  QueryPredDataFree free_fcn;
1895 
1896  g_return_if_fail (pdata);
1897  g_return_if_fail (pdata->type_name);
1898 
1899  free_fcn = qof_query_predicate_free (pdata->type_name);
1900  free_fcn (pdata);
1901 }
1902 
1905 {
1906  QueryPredicateCopyFunc copy;
1907 
1908  g_return_val_if_fail (pdata, NULL);
1909  g_return_val_if_fail (pdata->type_name, NULL);
1910 
1911  copy = qof_query_copy_predicate (pdata->type_name);
1912  return (copy (pdata));
1913 }
1914 
1915 gchar *
1916 qof_query_core_to_string (QofType type, gpointer object,
1917  QofParam * getter)
1918 {
1919  QueryToString toString;
1920 
1921  g_return_val_if_fail (type, NULL);
1922  g_return_val_if_fail (object, NULL);
1923  g_return_val_if_fail (getter, NULL);
1924 
1925  toString = g_hash_table_lookup (toStringTable, type);
1926  g_return_val_if_fail (toString, NULL);
1927 
1928  return toString (object, getter);
1929 }
1930 
1931 gboolean
1932 qof_query_core_predicate_equal (QofQueryPredData * p1,
1933  QofQueryPredData * p2)
1934 {
1935  QueryPredicateEqual pred_equal;
1936 
1937  if (p1 == p2)
1938  return TRUE;
1939  if (!p1 || !p2)
1940  return FALSE;
1941 
1942  if (p1->how != p2->how)
1943  return FALSE;
1944  if (safe_strcmp (p1->type_name, p2->type_name))
1945  return FALSE;
1946 
1947  pred_equal = g_hash_table_lookup (predEqualTable, p1->type_name);
1948  g_return_val_if_fail (pred_equal, FALSE);
1949 
1950  return pred_equal (p1, p2);
1951 }
gboolean guid_equal(const GUID *guid_1, const GUID *guid_2)
Definition: guid.c:620
#define QOF_DATE_FORMAT_UTC
QOF UTC format, xsd:date compatible. QOF_UTC_DATE_FORMAT "%Y-%m-%dT%H:%M:%SZ".
Definition: qofdate.h:277
gint qof_collection_compare(QofCollection *target, QofCollection *merge)
Compare two secondary collections.
Definition: qofid.c:264
QofQueryPredData * qof_query_kvp_predicate_path(QofQueryCompare how, const gchar *path, const KvpValue *value)
#define QOF_TYPE_COLLECT
secondary collections are used for one-to-many references between entities and are implemented using ...
Definition: qofclass.h:121
gint qof_numeric_compare(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:169
struct _QofNumeric QofNumeric
A rational-number type.
Definition: qofnumeric.h:61
QofDate * qof_date_from_qtime(const QofTime *qt)
Definition: qofdate.c:884
void qof_query_core_predicate_free(QofQueryPredData *pdata)
GUID * guid_malloc(void)
Definition: guid.c:64
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
gint safe_strcasecmp(const gchar *da, const gchar *db)
Definition: qofutil.c:95
gchar * qof_date_print(const QofDate *date, QofDateFormat df)
Convert a QofDate to a timestamp according to the specified date format.
Definition: qofdate.c:581
QofStringMatch
Definition: qofquerycore.h:65
gboolean qof_time_set_day_start(QofTime *qt)
set the given QofTime to the first second of that day.
Definition: qoftime.c:374
gboolean qof_numeric_equal(QofNumeric a, QofNumeric b)
Definition: qofnumeric.c:228
Full range replacement for struct tm.
Definition: qofdate.h:138
struct QofCollection_s QofCollection
Definition: qofid.h:138
struct _KvpValue KvpValue
Definition: kvpframe.h:78
QofNumeric qof_numeric_abs(QofNumeric a)
Definition: qofnumeric.c:645
QofGuidMatch
Definition: qofquerycore.h:104
KvpValue * kvp_value_copy(const KvpValue *value)
Definition: kvpframe.c:1598
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:392
gint qof_time_cmp(const QofTime *ta, const QofTime *tb)
Definition: qoftime.c:165
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
QofQueryPredData * qof_query_core_predicate_copy(QofQueryPredData *pdata)
gboolean qof_time_equal(const QofTime *ta, const QofTime *tb)
Definition: qoftime.c:148
QofQueryCompare
Definition: qofquerycore.h:51
QofCharMatch
Definition: qofquerycore.h:127
const gchar * QofType
Definition: qofclass.h:125
QofNumeric qof_numeric_sub(QofNumeric a, QofNumeric b, gint64 denom, gint how)
Definition: qofnumeric.c:383
Definition: guid.h:53
gchar * qof_numeric_to_string(QofNumeric n)
Definition: qofnumeric.c:1084
gboolean qof_query_time_predicate_get_time(QofQueryPredData *pd, QofTime *qt)
Definition: qofquerycore.c:381
gboolean qof_numeric_negative_p(QofNumeric a)
Definition: qofnumeric.c:132
#define PWARN(format, args...)
Definition: qoflog.h:191
struct QofTime64 QofTime
Use a 64-bit signed int QofTime.
Definition: qoftime.h:112
void qof_collection_destroy(QofCollection *col)
Definition: qofid.c:132
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
gboolean qof_numeric_positive_p(QofNumeric a)
Definition: qofnumeric.c:150
QofDateMatch
Definition: qofquerycore.h:78
gchar * qof_query_core_to_string(QofType type, gpointer object, QofParam *getter)
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:75
QofQueryPredData * qof_query_kvp_predicate(QofQueryCompare how, GSList *path, const KvpValue *value)
void kvp_value_delete(KvpValue *value)
Definition: kvpframe.c:1358
KvpValue * kvp_frame_get_slot_path_gslist(KvpFrame *frame, GSList *key_path)
Definition: kvpframe.c:1095
#define QOF_TYPE_CHOICE
Identify an object as containing a choice.
Definition: qofchoice.h:103
gint kvp_value_compare(const KvpValue *kva, const KvpValue *kvb)
Definition: kvpframe.c:1654
QofNumericMatch
Definition: qofquerycore.h:96
const gchar * QofLogModule
Definition: qofid.h:85