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