Branch data 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 : 52 : string_compare_func (gpointer a, gpointer b, gint options,
195 : : QofParam *getter)
196 : : {
197 : : const char *s1, *s2;
198 : 52 : g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
199 : :
200 : 52 : s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
201 : 52 : s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
202 : :
203 : 52 : if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
204 : 0 : return safe_strcasecmp (s1, s2);
205 : :
206 : 52 : 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 : 8 : 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 : 8 : g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
242 : :
243 : 8 : s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
244 : 8 : s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
245 : :
246 : : // Deal with nullptr strings
247 : 8 : if (s1 == s2) return 0;
248 : 8 : if (!s1 && s2) return -1;
249 : 8 : if (s1 && !s2) return 1;
250 : :
251 : : // Convert to integers and test
252 : 8 : i1 = strtol(s1, &sr1, 10);
253 : 8 : i2 = strtol(s2, &sr2, 10);
254 : 8 : if (i1 < i2) return -1;
255 : 8 : if (i1 > i2) return 1;
256 : :
257 : : // If the integers match, then test the REST of the string as text.
258 : 8 : if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
259 : 0 : return safe_strcasecmp (sr1, sr2);
260 : :
261 : 8 : 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 : 10759 : date_compare (time64 ta, time64 tb, QofDateMatch options)
353 : : {
354 : :
355 : 10759 : if (options == QOF_DATE_MATCH_DAY)
356 : : {
357 : 0 : ta = time64CanonicalDayTime (ta);
358 : 0 : tb = time64CanonicalDayTime (tb);
359 : : }
360 : :
361 : 10759 : if (ta < tb)
362 : 4136 : return -1;
363 : 6623 : if (ta > tb)
364 : 6210 : 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 : 398 : date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
404 : : {
405 : : time64 ta, tb;
406 : :
407 : 398 : g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
408 : :
409 : 398 : ta = ((query_date_getter)getter->param_getfcn) (a, getter);
410 : 398 : tb = ((query_date_getter)getter->param_getfcn) (b, getter);
411 : :
412 : 398 : 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 : 8 : numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
544 : : {
545 : : gnc_numeric va, vb;
546 : :
547 : 8 : g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
548 : :
549 : 8 : va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
550 : 8 : vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
551 : :
552 : 8 : 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 : : }
|