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
string_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
string_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
string_free_pdata(QofQueryPredData * pd)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 *
string_copy_predicate(QofQueryPredData * pd)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
string_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
233 QofQueryPredData *
qof_query_string_predicate(QofQueryCompare how,const gchar * str,QofStringMatch options,gboolean is_regex)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 *
string_to_string(gpointer object,QofParam * getter)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
time_compare(QofTime * ta,QofTime * tb,QofDateMatch options)276 time_compare (QofTime *ta, QofTime *tb, QofDateMatch options)
277 {
278 if (options == QOF_DATE_MATCH_DAY)
279 {
280 qof_time_set_day_start (ta);
281 qof_time_set_day_start (tb);
282 }
283 return qof_time_cmp (ta, tb);
284 }
285
286 static int
time_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
time_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
time_free_pdata(QofQueryPredData * pd)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 *
time_copy_predicate(QofQueryPredData * pd)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
time_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
366 QofQueryPredData *
qof_query_time_predicate(QofQueryCompare how,QofDateMatch options,QofTime * qt)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
qof_query_time_predicate_get_time(QofQueryPredData * pd,QofTime * qt)381 qof_query_time_predicate_get_time (QofQueryPredData * pd,
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 *
time_to_string(gpointer object,QofParam * getter)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
numeric_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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 =
438 (qof_numeric_compare (qof_numeric_abs
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
numeric_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
numeric_free_pdata(QofQueryPredData * pd)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 *
numeric_copy_predicate(QofQueryPredData * pd)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
numeric_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
511 QofQueryPredData *
qof_query_numeric_predicate(QofQueryCompare how,QofNumericMatch options,QofNumeric value)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 *
numeric_to_string(gpointer object,QofParam * getter)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 *
debcred_to_string(gpointer object,QofParam * getter)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
guid_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
591 case QOF_GUID_MATCH_LIST_ANY:
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:
642 case QOF_GUID_MATCH_LIST_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
guid_free_pdata(QofQueryPredData * pd)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 *
guid_copy_predicate(QofQueryPredData * pd)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
guid_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
699 QofQueryPredData *
qof_query_guid_predicate(QofGuidMatch options,GList * guid_list)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
int32_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
int32_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
int32_free_pdata(QofQueryPredData * pd)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 *
int32_copy_predicate(QofQueryPredData * pd)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
int32_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
801 QofQueryPredData *
qof_query_int32_predicate(QofQueryCompare how,gint32 val)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 *
int32_to_string(gpointer object,QofParam * getter)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
int64_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
int64_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
int64_free_pdata(QofQueryPredData * pd)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 *
int64_copy_predicate(QofQueryPredData * pd)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
int64_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
897 QofQueryPredData *
qof_query_int64_predicate(QofQueryCompare how,gint64 val)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 *
int64_to_string(gpointer object,QofParam * getter)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
double_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
double_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
double_free_pdata(QofQueryPredData * pd)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 *
double_copy_predicate(QofQueryPredData * pd)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
double_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
993 QofQueryPredData *
qof_query_double_predicate(QofQueryCompare how,double val)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 *
double_to_string(gpointer object,QofParam * getter)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
boolean_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
boolean_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
boolean_free_pdata(QofQueryPredData * pd)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 *
boolean_copy_predicate(QofQueryPredData * pd)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
boolean_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
1078 QofQueryPredData *
qof_query_boolean_predicate(QofQueryCompare how,gboolean val)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 *
boolean_to_string(gpointer object,QofParam * getter)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
char_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
char_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
char_free_pdata(QofQueryPredData * pd)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 *
char_copy_predicate(QofQueryPredData * pd)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
char_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
1170 QofQueryPredData *
qof_query_char_predicate(QofCharMatch options,const char * chars)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 *
char_to_string(gpointer object,QofParam * getter)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
kvp_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
kvp_free_pdata(QofQueryPredData * pd)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 *
kvp_copy_predicate(QofQueryPredData * pd)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
kvp_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
1284 QofQueryPredData *
qof_query_kvp_predicate(QofQueryCompare how,GSList * path,const KvpValue * value)1285 qof_query_kvp_predicate (QofQueryCompare how,
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
1304 QofQueryPredData *
qof_query_kvp_predicate_path(QofQueryCompare how,const char * path,const KvpValue * value)1305 qof_query_kvp_predicate_path (QofQueryCompare how,
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
collect_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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 }
1376 case QOF_GUID_MATCH_LIST_ANY:
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:
1414 case QOF_GUID_MATCH_LIST_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
collect_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)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
collect_free_pdata(QofQueryPredData * pd)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 *
collect_copy_predicate(QofQueryPredData * pd)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
collect_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
query_collect_cb(QofEntity * ent,gpointer user_data)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
1510 QofQueryPredData *
qof_query_collect_predicate(QofGuidMatch options,QofCollection * coll)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
choice_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)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
1576 case QOF_GUID_MATCH_LIST_ANY:
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:
1617 case QOF_GUID_MATCH_LIST_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
choice_free_pdata(QofQueryPredData * pd)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 *
choice_copy_predicate(QofQueryPredData * pd)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
choice_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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
1674 QofQueryPredData *
qof_query_choice_predicate(QofGuidMatch options,GList * guid_list)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 ================================================== */
1700 /** This function registers a new Core Object with the QofQuery
1701 * subsystem. It maps the "core_name" object to the given
1702 * query_predicate, predicate_copy, and predicate_data_free functions.
1703 *
1704 * An example:
1705 * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
1706 * string_compare_fcn, string_free_pdata,
1707 * string_print_fcn, pred_equal_fcn);
1708 */
1709
1710
1711 static void
qof_query_register_core_object(QofType core_name,QofQueryPredicateFunc pred,QofCompareFunc comp,QueryPredicateCopyFunc copy,QueryPredDataFree pd_free,QueryToString toString,QueryPredicateEqual pred_equal)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
init_tables(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
qof_query_copy_predicate(QofType type)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
qof_query_predicate_free(QofType type)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
qof_query_core_init(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
qof_query_core_shutdown(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
qof_query_core_get_predicate(QofType type)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
qof_query_core_get_compare(QofType type)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
qof_query_core_predicate_free(QofQueryPredData * pdata)1892 qof_query_core_predicate_free (QofQueryPredData * pdata)
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
1903 QofQueryPredData *
qof_query_core_predicate_copy(QofQueryPredData * pdata)1904 qof_query_core_predicate_copy (QofQueryPredData * pdata)
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 *
qof_query_core_to_string(QofType type,gpointer object,QofParam * getter)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
qof_query_core_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)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 }
1952