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