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