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