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