1 /********************************************************************\
2  * QueryCore.c -- API for providing core Query data types           *
3  * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>                *
4  * Copyright (C) 2006-2008 Neil Williams <linux@codehelp.co.uk>     *
5  *                                                                  *
6  * This program is free software; you can redistribute it and/or    *
7  * modify it under the terms of the GNU General Public License as   *
8  * published by the Free Software Foundation; either version 2 of   *
9  * the License, or (at your option) any later version.              *
10  *                                                                  *
11  * This program is distributed in the hope that it will be useful,  *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
14  * GNU General Public License for more details.                     *
15  *                                                                  *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact:                        *
18  *                                                                  *
19  * Free Software Foundation           Voice:  +1-617-542-5942       *
20  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
21  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
22  *                                                                  *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <glib.h>
28 
29 #include "qof.h"
30 #include "qofquerycore-p.h"
31 
32 static QofLogModule log_module = QOF_MOD_QUERY;
33 
34 /* A function to destroy a query predicate's pdata */
35 typedef void (*QueryPredDataFree) (QofQueryPredData * pdata);
36 
37 /* A function to copy a query's predicate data */
38 typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData *
39 	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 gchar *(*QueryToString) (gpointer object, QofParam * getter);
48 
49 /* A function to test for equality of predicate data */
50 typedef gboolean (*QueryPredicateEqual) (QofQueryPredData * p1,
51 	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 gchar *(*query_string_getter) (gpointer, QofParam *);
58 static const gchar *query_string_type = QOF_TYPE_STRING;
59 
60 typedef QofTime *(*query_time_getter) (gpointer, QofParam *);
61 static const gchar *query_time_type = QOF_TYPE_TIME;
62 
63 typedef QofNumeric (*query_numeric_getter) (gpointer, QofParam *);
64 static const gchar *query_numeric_type = QOF_TYPE_NUMERIC;
65 
66 typedef GList *(*query_glist_getter) (gpointer, QofParam *);
67 typedef const GUID *(*query_guid_getter) (gpointer, QofParam *);
68 static const gchar *query_guid_type = QOF_TYPE_GUID;
69 
70 typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
71 static const gchar *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 gchar *query_double_type = QOF_TYPE_DOUBLE;
78 
79 typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
80 static const gchar *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 KvpFrame *(*query_kvp_getter) (gpointer, QofParam *);
86 static const gchar *query_kvp_type = QOF_TYPE_KVP;
87 
88 typedef QofCollection *(*query_collect_getter) (gpointer, QofParam *);
89 static const gchar *query_collect_type = QOF_TYPE_COLLECT;
90 
91 typedef const GUID *(*query_choice_getter) (gpointer, QofParam *);
92 static const gchar *query_choice_type = QOF_TYPE_CHOICE;
93 
94 /* Tables for predicate storage and lookup */
95 static gboolean initialized = FALSE;
96 static GHashTable *predTable = NULL;
97 static GHashTable *cmpTable = NULL;
98 static GHashTable *copyTable = NULL;
99 static GHashTable *freeTable = NULL;
100 static GHashTable *toStringTable = NULL;
101 static GHashTable *predEqualTable = NULL;
102 
103 #define COMPARE_ERROR -3
104 #define PREDICATE_ERROR -2
105 
106 #define VERIFY_PDATA(str) { \
107         g_return_if_fail (pd != NULL); \
108         g_return_if_fail (pd->type_name == str || \
109                         !safe_strcmp (str, pd->type_name)); \
110 }
111 #define VERIFY_PDATA_R(str) { \
112         g_return_val_if_fail (pd != NULL, NULL); \
113         g_return_val_if_fail (pd->type_name == str || \
114                                 !safe_strcmp (str, pd->type_name), \
115                                 NULL); \
116 }
117 #define VERIFY_PREDICATE(str) { \
118         g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
119         g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
120         g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
121         g_return_val_if_fail (pd->type_name == str || \
122                                 !safe_strcmp (str, pd->type_name), \
123                                 PREDICATE_ERROR); \
124 }
125 
126 /* *******************************************************************/
127 /* TYPE-HANDLING FUNCTIONS */
128 
129 /* QOF_TYPE_STRING */
130 
131 static gint
string_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)132 string_match_predicate (gpointer object,
133 	QofParam * getter, QofQueryPredData * pd)
134 {
135 	query_string_t pdata = (query_string_t) pd;
136 	const gchar *s;
137 	gint ret = 0;
138 
139 	VERIFY_PREDICATE (query_string_type);
140 
141 	s = ((query_string_getter) getter->param_getfcn) (object, getter);
142 
143 	if (!s)
144 		s = "";
145 
146 	if (pdata->is_regex)
147 	{
148 		regmatch_t match;
149 		if (!regexec (&pdata->compiled, s, 1, &match, 0))
150 			ret = 1;
151 
152 	}
153 	else if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE)
154 	{
155 		if (strcasestr (s, pdata->matchstring))
156 			ret = 1;
157 
158 	}
159 	else
160 	{
161 		if (strstr (s, pdata->matchstring))
162 			ret = 1;
163 	}
164 
165 	switch (pd->how)
166 	{
167 	case QOF_COMPARE_EQUAL:
168 		return ret;
169 	case QOF_COMPARE_NEQ:
170 		return !ret;
171 	default:
172 		PWARN ("bad match type: %d", pd->how);
173 		return 0;
174 	}
175 }
176 
177 static gint
string_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)178 string_compare_func (gpointer a, gpointer b, gint options,
179 	QofParam * getter)
180 {
181 	const gchar *s1, *s2;
182 	g_return_val_if_fail (a && b && getter
183 		&& getter->param_getfcn, COMPARE_ERROR);
184 
185 	s1 = ((query_string_getter) getter->param_getfcn) (a, getter);
186 	s2 = ((query_string_getter) getter->param_getfcn) (b, getter);
187 
188 	if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
189 		return safe_strcasecmp (s1, s2);
190 
191 	return safe_strcmp (s1, s2);
192 }
193 
194 static void
string_free_pdata(QofQueryPredData * pd)195 string_free_pdata (QofQueryPredData * pd)
196 {
197 	query_string_t pdata = (query_string_t) pd;
198 
199 	VERIFY_PDATA (query_string_type);
200 
201 	if (pdata->is_regex)
202 		regfree (&pdata->compiled);
203 	else
204 		g_free (pdata->matchstring);
205 
206 	g_free (pdata);
207 }
208 
209 static QofQueryPredData *
string_copy_predicate(QofQueryPredData * pd)210 string_copy_predicate (QofQueryPredData * pd)
211 {
212 	query_string_t pdata = (query_string_t) pd;
213 
214 	VERIFY_PDATA_R (query_string_type);
215 
216 	return qof_query_string_predicate (pd->how, pdata->matchstring,
217 		pdata->options, pdata->is_regex);
218 }
219 
220 static gboolean
string_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)221 string_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
222 {
223 	query_string_t pd1 = (query_string_t) p1;
224 	query_string_t pd2 = (query_string_t) p2;
225 
226 	if (pd1->options != pd2->options)
227 		return FALSE;
228 	if (pd1->is_regex != pd2->is_regex)
229 		return FALSE;
230 	return (safe_strcmp (pd1->matchstring, pd2->matchstring) == 0);
231 }
232 
233 QofQueryPredData *
qof_query_string_predicate(QofQueryCompare how,const gchar * str,QofStringMatch options,gboolean is_regex)234 qof_query_string_predicate (QofQueryCompare how,
235 	const gchar *str, QofStringMatch options, gboolean is_regex)
236 {
237 	query_string_t pdata;
238 
239 	g_return_val_if_fail (str, NULL);
240 	g_return_val_if_fail (*str != '\0', NULL);
241 	g_return_val_if_fail (how == QOF_COMPARE_EQUAL
242 		|| how == QOF_COMPARE_NEQ, NULL);
243 
244 	pdata = g_new0 (query_string_def, 1);
245 	pdata->pd.type_name = query_string_type;
246 	pdata->pd.how = how;
247 	pdata->options = options;
248 	pdata->matchstring = g_strdup (str);
249 
250 	if (is_regex)
251 	{
252 		int flags = REG_EXTENDED;
253 		if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
254 			flags |= REG_ICASE;
255 
256 		regcomp (&pdata->compiled, str, flags);
257 		pdata->is_regex = TRUE;
258 	}
259 
260 	return ((QofQueryPredData *) pdata);
261 }
262 
263 static gchar *
string_to_string(gpointer object,QofParam * getter)264 string_to_string (gpointer object, QofParam * getter)
265 {
266 	const char *res;
267 	res = ((query_string_getter) getter->param_getfcn) (object, getter);
268 	if (res)
269 		return g_strdup (res);
270 	return NULL;
271 }
272 
273 /* QOF_TYPE_TIME */
274 
275 static gint
time_compare(QofTime * ta,QofTime * tb,QofDateMatch options)276 time_compare (QofTime *ta, QofTime *tb, QofDateMatch options)
277 {
278 	if (options == QOF_DATE_MATCH_DAY)
279 	{
280 		qof_time_set_day_start (ta);
281 		qof_time_set_day_start (tb);
282 	}
283 	return qof_time_cmp (ta, tb);
284 }
285 
286 static int
time_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)287 time_match_predicate (gpointer object, QofParam * getter,
288 					  QofQueryPredData * pd)
289 {
290 	query_time_t pdata = (query_time_t) pd;
291 	QofTime *objtime;
292 	gint compare;
293 
294 	VERIFY_PREDICATE (query_time_type);
295 
296 	objtime = ((query_time_getter) getter->param_getfcn) (object, getter);
297 	compare = time_compare (objtime, pdata->qt, pdata->options);
298 
299 	switch (pd->how)
300 	{
301 	case QOF_COMPARE_LT:
302 		return (compare < 0);
303 	case QOF_COMPARE_LTE:
304 		return (compare <= 0);
305 	case QOF_COMPARE_EQUAL:
306 		return (compare == 0);
307 	case QOF_COMPARE_GT:
308 		return (compare > 0);
309 	case QOF_COMPARE_GTE:
310 		return (compare >= 0);
311 	case QOF_COMPARE_NEQ:
312 		return (compare != 0);
313 	default:
314 		PWARN ("bad match type: %d", pd->how);
315 		return 0;
316 	}
317 }
318 
319 static gint
time_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)320 time_compare_func (gpointer a, gpointer b, gint options,
321 				   QofParam * getter)
322 {
323 	QofTime *ta, *tb;
324 
325 	g_return_val_if_fail (a && b && getter
326 		&& getter->param_getfcn, COMPARE_ERROR);
327 
328 	ta = ((query_time_getter) getter->param_getfcn) (a, getter);
329 	tb = ((query_time_getter) getter->param_getfcn) (b, getter);
330 
331 	return time_compare (ta, tb, options);
332 }
333 
334 static void
time_free_pdata(QofQueryPredData * pd)335 time_free_pdata (QofQueryPredData * pd)
336 {
337 	query_time_t pdata = (query_time_t) pd;
338 
339 	VERIFY_PDATA (query_time_type);
340 
341 	g_free (pdata);
342 }
343 
344 static QofQueryPredData *
time_copy_predicate(QofQueryPredData * pd)345 time_copy_predicate (QofQueryPredData * pd)
346 {
347 	query_time_t pdata = (query_time_t) pd;
348 
349 	VERIFY_PDATA_R (query_time_type);
350 
351 	return qof_query_time_predicate (pd->how, pdata->options,
352 		pdata->qt);
353 }
354 
355 static gboolean
time_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)356 time_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
357 {
358 	query_time_t pd1 = (query_time_t) p1;
359 	query_time_t pd2 = (query_time_t) p2;
360 
361 	if (pd1->options != pd2->options)
362 		return FALSE;
363 	return qof_time_equal (pd1->qt, pd2->qt);
364 }
365 
366 QofQueryPredData *
qof_query_time_predicate(QofQueryCompare how,QofDateMatch options,QofTime * qt)367 qof_query_time_predicate (QofQueryCompare how,
368 	QofDateMatch options, QofTime *qt)
369 {
370 	query_time_t pdata;
371 
372 	pdata = g_new0 (query_time_def, 1);
373 	pdata->pd.type_name = query_time_type;
374 	pdata->pd.how = how;
375 	pdata->options = options;
376 	pdata->qt = qt;
377 	return ((QofQueryPredData *) pdata);
378 }
379 
380 gboolean
qof_query_time_predicate_get_time(QofQueryPredData * pd,QofTime * qt)381 qof_query_time_predicate_get_time (QofQueryPredData * pd,
382 								   QofTime *qt)
383 {
384 	query_time_t pdata = (query_time_t) pd;
385 
386 	if (pdata->pd.type_name != query_time_type)
387 		return FALSE;
388 	qt = pdata->qt;
389 	return TRUE;
390 }
391 
392 static gchar *
time_to_string(gpointer object,QofParam * getter)393 time_to_string (gpointer object, QofParam * getter)
394 {
395 	QofDate *qd;
396 	QofTime *qt =
397 		((query_time_getter) getter->param_getfcn) (object, getter);
398 
399 	qd = qof_date_from_qtime (qt);
400 	return qof_date_print (qd, QOF_DATE_FORMAT_UTC);
401 }
402 
403 /* QOF_TYPE_NUMERIC ================================================= */
404 
405 static int
numeric_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)406 numeric_match_predicate (gpointer object, QofParam * getter,
407 	QofQueryPredData * pd)
408 {
409 	query_numeric_t pdata = (query_numeric_t) pd;
410 	QofNumeric obj_val;
411 	gint compare;
412 
413 	VERIFY_PREDICATE (query_numeric_type);
414 
415 	obj_val =
416 		((query_numeric_getter) getter->param_getfcn) (object, getter);
417 
418 	switch (pdata->options)
419 	{
420 	case QOF_NUMERIC_MATCH_CREDIT:
421 		if (qof_numeric_positive_p (obj_val))
422 			return 0;
423 		break;
424 	case QOF_NUMERIC_MATCH_DEBIT:
425 		if (qof_numeric_negative_p (obj_val))
426 			return 0;
427 		break;
428 	default:
429 		break;
430 	}
431 
432 	/* Amounts are considered to be 'equal' if they match to
433 	 * four decimal places. (epsilon=1/10000) */
434 	if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ)
435 	{
436 		QofNumeric cmp_val = qof_numeric_create (1, 10000);
437 		compare =
438 			(qof_numeric_compare (qof_numeric_abs
439 				(qof_numeric_sub (qof_numeric_abs (obj_val),
440 						qof_numeric_abs (pdata->
441 							amount),
442 						100000, QOF_HOW_RND_ROUND)), cmp_val) < 0);
443 	}
444 	else
445 		compare =
446 			qof_numeric_compare (qof_numeric_abs (obj_val), pdata->amount);
447 
448 	switch (pd->how)
449 	{
450 	case QOF_COMPARE_LT:
451 		return (compare < 0);
452 	case QOF_COMPARE_LTE:
453 		return (compare <= 0);
454 	case QOF_COMPARE_EQUAL:
455 		return compare;
456 	case QOF_COMPARE_GT:
457 		return (compare > 0);
458 	case QOF_COMPARE_GTE:
459 		return (compare >= 0);
460 	case QOF_COMPARE_NEQ:
461 		return !compare;
462 	default:
463 		PWARN ("bad match type: %d", pd->how);
464 		return 0;
465 	}
466 }
467 
468 static int
numeric_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)469 numeric_compare_func (gpointer a, gpointer b,
470 	gint options __attribute__ ((unused)), QofParam * getter)
471 {
472 	QofNumeric va, vb;
473 
474 	g_return_val_if_fail (a && b && getter
475 		&& getter->param_getfcn, COMPARE_ERROR);
476 
477 	va = ((query_numeric_getter) getter->param_getfcn) (a, getter);
478 	vb = ((query_numeric_getter) getter->param_getfcn) (b, getter);
479 
480 	return qof_numeric_compare (va, vb);
481 }
482 
483 static void
numeric_free_pdata(QofQueryPredData * pd)484 numeric_free_pdata (QofQueryPredData * pd)
485 {
486 	query_numeric_t pdata = (query_numeric_t) pd;
487 	VERIFY_PDATA (query_numeric_type);
488 	g_free (pdata);
489 }
490 
491 static QofQueryPredData *
numeric_copy_predicate(QofQueryPredData * pd)492 numeric_copy_predicate (QofQueryPredData * pd)
493 {
494 	query_numeric_t pdata = (query_numeric_t) pd;
495 	VERIFY_PDATA_R (query_numeric_type);
496 	return qof_query_numeric_predicate (pd->how, pdata->options,
497 		pdata->amount);
498 }
499 
500 static gboolean
numeric_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)501 numeric_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
502 {
503 	query_numeric_t pd1 = (query_numeric_t) p1;
504 	query_numeric_t pd2 = (query_numeric_t) p2;
505 
506 	if (pd1->options != pd2->options)
507 		return FALSE;
508 	return qof_numeric_equal (pd1->amount, pd2->amount);
509 }
510 
511 QofQueryPredData *
qof_query_numeric_predicate(QofQueryCompare how,QofNumericMatch options,QofNumeric value)512 qof_query_numeric_predicate (QofQueryCompare how,
513 	QofNumericMatch options, QofNumeric value)
514 {
515 	query_numeric_t pdata;
516 	pdata = g_new0 (query_numeric_def, 1);
517 	pdata->pd.type_name = query_numeric_type;
518 	pdata->pd.how = how;
519 	pdata->options = options;
520 	pdata->amount = value;
521 	return ((QofQueryPredData *) pdata);
522 }
523 
524 static char *
numeric_to_string(gpointer object,QofParam * getter)525 numeric_to_string (gpointer object, QofParam * getter)
526 {
527 	QofNumeric num;
528 	num = ((query_numeric_getter) getter->param_getfcn) (object, getter);
529 
530 	return qof_numeric_to_string (num);
531 }
532 
533 static char *
debcred_to_string(gpointer object,QofParam * getter)534 debcred_to_string (gpointer object, QofParam * getter)
535 {
536 	QofNumeric num;
537 	num = ((query_numeric_getter) getter->param_getfcn) (object, getter);
538 
539 	return qof_numeric_to_string (num);
540 }
541 
542 /* QOF_TYPE_GUID =================================================== */
543 
544 static int
guid_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)545 guid_match_predicate (gpointer object, QofParam * getter,
546 	QofQueryPredData * pd)
547 {
548 	query_guid_t pdata = (query_guid_t) pd;
549 	GList *node, *o_list;
550 	const GUID *guid = NULL;
551 
552 	VERIFY_PREDICATE (query_guid_type);
553 
554 	switch (pdata->options)
555 	{
556 
557 	case QOF_GUID_MATCH_ALL:
558 		/* object is a GList of objects; param_getfcn must be called on each one.
559 		 * See if every guid in the predicate is accounted-for in the
560 		 * object list
561 		 */
562 
563 		for (node = pdata->guids; node; node = node->next)
564 		{
565 			/* See if this GUID matches the object's guid */
566 			for (o_list = object; o_list; o_list = o_list->next)
567 			{
568 				guid =
569 					((query_guid_getter) getter->param_getfcn) (o_list->
570 					data, getter);
571 				if (guid_equal (node->data, guid))
572 					break;
573 			}
574 
575 			/*
576 			 * If o_list is NULL, we've walked the whole list without finding
577 			 * a match.  Therefore break out now, the match has failed.
578 			 */
579 			if (o_list == NULL)
580 				break;
581 		}
582 
583 		/*
584 		 * The match is complete.  If node == NULL then we've succesfully
585 		 * found a match for all the guids in the predicate.  Return
586 		 * appropriately below.
587 		 */
588 
589 		break;
590 
591 	case QOF_GUID_MATCH_LIST_ANY:
592 		/* object is a single object, getter returns a GList* of GUID*
593 		 *
594 		 * See if any GUID* in the returned list matches any guid in the
595 		 * predicate match list.
596 		 */
597 
598 		o_list =
599 			((query_glist_getter) getter->param_getfcn) (object, getter);
600 
601 		for (node = o_list; node; node = node->next)
602 		{
603 			GList *node2;
604 
605 			/* Search the predicate data for a match */
606 			for (node2 = pdata->guids; node2; node2 = node2->next)
607 			{
608 				if (guid_equal (node->data, node2->data))
609 					break;
610 			}
611 
612 			/* Check to see if we found a match.  If so, break now */
613 			if (node2 != NULL)
614 				break;
615 		}
616 
617 		g_list_free (o_list);
618 
619 		/* yea, node may point to an invalid location, but that's ok.
620 		 * we're not _USING_ the value, just checking that it's non-NULL
621 		 */
622 
623 		break;
624 
625 	default:
626 		/* object is a single object, getter returns a GUID*
627 		 *
628 		 * See if the guid is in the list
629 		 */
630 
631 		guid = ((query_guid_getter) getter->param_getfcn) (object, getter);
632 		for (node = pdata->guids; node; node = node->next)
633 		{
634 			if (guid_equal (node->data, guid))
635 				break;
636 		}
637 	}
638 
639 	switch (pdata->options)
640 	{
641 	case QOF_GUID_MATCH_ANY:
642 	case QOF_GUID_MATCH_LIST_ANY:
643 		return (node != NULL);
644 		break;
645 	case QOF_GUID_MATCH_NONE:
646 	case QOF_GUID_MATCH_ALL:
647 		return (node == NULL);
648 		break;
649 	case QOF_GUID_MATCH_NULL:
650 		return (guid == NULL);
651 		break;
652 	default:
653 		PWARN ("bad match type");
654 		return 0;
655 	}
656 }
657 
658 static void
guid_free_pdata(QofQueryPredData * pd)659 guid_free_pdata (QofQueryPredData * pd)
660 {
661 	query_guid_t pdata = (query_guid_t) pd;
662 	GList *node;
663 	VERIFY_PDATA (query_guid_type);
664 	for (node = pdata->guids; node; node = node->next)
665 	{
666 		guid_free (node->data);
667 	}
668 	g_list_free (pdata->guids);
669 	g_free (pdata);
670 }
671 
672 static QofQueryPredData *
guid_copy_predicate(QofQueryPredData * pd)673 guid_copy_predicate (QofQueryPredData * pd)
674 {
675 	query_guid_t pdata = (query_guid_t) pd;
676 	VERIFY_PDATA_R (query_guid_type);
677 	return qof_query_guid_predicate (pdata->options, pdata->guids);
678 }
679 
680 static gboolean
guid_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)681 guid_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
682 {
683 	query_guid_t pd1 = (query_guid_t) p1;
684 	query_guid_t pd2 = (query_guid_t) p2;
685 	GList *l1 = pd1->guids, *l2 = pd2->guids;
686 
687 	if (pd1->options != pd2->options)
688 		return FALSE;
689 	if (g_list_length (l1) != g_list_length (l2))
690 		return FALSE;
691 	for (; l1; l1 = l1->next, l2 = l2->next)
692 	{
693 		if (!guid_equal (l1->data, l2->data))
694 			return FALSE;
695 	}
696 	return TRUE;
697 }
698 
699 QofQueryPredData *
qof_query_guid_predicate(QofGuidMatch options,GList * guid_list)700 qof_query_guid_predicate (QofGuidMatch options, GList * guid_list)
701 {
702 	query_guid_t pdata;
703 	GList *node;
704 
705 	if (NULL == guid_list)
706 		return NULL;
707 
708 	pdata = g_new0 (query_guid_def, 1);
709 	pdata->pd.how = QOF_COMPARE_EQUAL;
710 	pdata->pd.type_name = query_guid_type;
711 	pdata->options = options;
712 
713 	pdata->guids = g_list_copy (guid_list);
714 	for (node = pdata->guids; node; node = node->next)
715 	{
716 		GUID *guid = guid_malloc ();
717 		*guid = *((GUID *) node->data);
718 		node->data = guid;
719 	}
720 	return ((QofQueryPredData *) pdata);
721 }
722 
723 /* ================================================================ */
724 /* QOF_TYPE_INT32 */
725 
726 static int
int32_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)727 int32_match_predicate (gpointer object, QofParam * getter,
728 	QofQueryPredData * pd)
729 {
730 	gint32 val;
731 	query_int32_t pdata = (query_int32_t) pd;
732 
733 	VERIFY_PREDICATE (query_int32_type);
734 
735 	val = ((query_int32_getter) getter->param_getfcn) (object, getter);
736 
737 	switch (pd->how)
738 	{
739 	case QOF_COMPARE_LT:
740 		return (val < pdata->val);
741 	case QOF_COMPARE_LTE:
742 		return (val <= pdata->val);
743 	case QOF_COMPARE_EQUAL:
744 		return (val == pdata->val);
745 	case QOF_COMPARE_GT:
746 		return (val > pdata->val);
747 	case QOF_COMPARE_GTE:
748 		return (val >= pdata->val);
749 	case QOF_COMPARE_NEQ:
750 		return (val != pdata->val);
751 	default:
752 		PWARN ("bad match type: %d", pd->how);
753 		return 0;
754 	}
755 }
756 
757 static int
int32_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)758 int32_compare_func (gpointer a, gpointer b,
759 	gint options __attribute__ ((unused)),
760 	QofParam * getter)
761 {
762 	gint32 v1, v2;
763 	g_return_val_if_fail (a && b && getter
764 		&& getter->param_getfcn, COMPARE_ERROR);
765 
766 	v1 = ((query_int32_getter) getter->param_getfcn) (a, getter);
767 	v2 = ((query_int32_getter) getter->param_getfcn) (b, getter);
768 
769 	if (v1 < v2)
770 		return -1;
771 	if (v1 > v2)
772 		return 1;
773 	return 0;
774 }
775 
776 static void
int32_free_pdata(QofQueryPredData * pd)777 int32_free_pdata (QofQueryPredData * pd)
778 {
779 	query_int32_t pdata = (query_int32_t) pd;
780 	VERIFY_PDATA (query_int32_type);
781 	g_free (pdata);
782 }
783 
784 static QofQueryPredData *
int32_copy_predicate(QofQueryPredData * pd)785 int32_copy_predicate (QofQueryPredData * pd)
786 {
787 	query_int32_t pdata = (query_int32_t) pd;
788 	VERIFY_PDATA_R (query_int32_type);
789 	return qof_query_int32_predicate (pd->how, pdata->val);
790 }
791 
792 static gboolean
int32_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)793 int32_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
794 {
795 	query_int32_t pd1 = (query_int32_t) p1;
796 	query_int32_t pd2 = (query_int32_t) p2;
797 
798 	return (pd1->val == pd2->val);
799 }
800 
801 QofQueryPredData *
qof_query_int32_predicate(QofQueryCompare how,gint32 val)802 qof_query_int32_predicate (QofQueryCompare how, gint32 val)
803 {
804 	query_int32_t pdata = g_new0 (query_int32_def, 1);
805 	pdata->pd.type_name = query_int32_type;
806 	pdata->pd.how = how;
807 	pdata->val = val;
808 	return ((QofQueryPredData *) pdata);
809 }
810 
811 static char *
int32_to_string(gpointer object,QofParam * getter)812 int32_to_string (gpointer object, QofParam * getter)
813 {
814 	gint32 num =
815 		((query_int32_getter) getter->param_getfcn) (object, getter);
816 
817 	return g_strdup_printf ("%d", num);
818 }
819 
820 /* ================================================================ */
821 /* QOF_TYPE_INT64 */
822 
823 static int
int64_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)824 int64_match_predicate (gpointer object, QofParam * getter,
825 	QofQueryPredData * pd)
826 {
827 	gint64 val;
828 	query_int64_t pdata = (query_int64_t) pd;
829 
830 	VERIFY_PREDICATE (query_int64_type);
831 
832 	val = ((query_int64_getter) getter->param_getfcn) (object, getter);
833 
834 	switch (pd->how)
835 	{
836 	case QOF_COMPARE_LT:
837 		return (val < pdata->val);
838 	case QOF_COMPARE_LTE:
839 		return (val <= pdata->val);
840 	case QOF_COMPARE_EQUAL:
841 		return (val == pdata->val);
842 	case QOF_COMPARE_GT:
843 		return (val > pdata->val);
844 	case QOF_COMPARE_GTE:
845 		return (val >= pdata->val);
846 	case QOF_COMPARE_NEQ:
847 		return (val != pdata->val);
848 	default:
849 		PWARN ("bad match type: %d", pd->how);
850 		return 0;
851 	}
852 }
853 
854 static int
int64_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)855 int64_compare_func (gpointer a, gpointer b,
856 	gint options __attribute__ ((unused)), QofParam * getter)
857 {
858 	gint64 v1, v2;
859 	g_return_val_if_fail (a && b && getter
860 		&& getter->param_getfcn, COMPARE_ERROR);
861 
862 	v1 = ((query_int64_getter) getter->param_getfcn) (a, getter);
863 	v2 = ((query_int64_getter) getter->param_getfcn) (b, getter);
864 
865 	if (v1 < v2)
866 		return -1;
867 	if (v1 > v2)
868 		return 1;
869 	return 0;
870 }
871 
872 static void
int64_free_pdata(QofQueryPredData * pd)873 int64_free_pdata (QofQueryPredData * pd)
874 {
875 	query_int64_t pdata = (query_int64_t) pd;
876 	VERIFY_PDATA (query_int64_type);
877 	g_free (pdata);
878 }
879 
880 static QofQueryPredData *
int64_copy_predicate(QofQueryPredData * pd)881 int64_copy_predicate (QofQueryPredData * pd)
882 {
883 	query_int64_t pdata = (query_int64_t) pd;
884 	VERIFY_PDATA_R (query_int64_type);
885 	return qof_query_int64_predicate (pd->how, pdata->val);
886 }
887 
888 static gboolean
int64_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)889 int64_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
890 {
891 	query_int64_t pd1 = (query_int64_t) p1;
892 	query_int64_t pd2 = (query_int64_t) p2;
893 
894 	return (pd1->val == pd2->val);
895 }
896 
897 QofQueryPredData *
qof_query_int64_predicate(QofQueryCompare how,gint64 val)898 qof_query_int64_predicate (QofQueryCompare how, gint64 val)
899 {
900 	query_int64_t pdata = g_new0 (query_int64_def, 1);
901 	pdata->pd.type_name = query_int64_type;
902 	pdata->pd.how = how;
903 	pdata->val = val;
904 	return ((QofQueryPredData *) pdata);
905 }
906 
907 static char *
int64_to_string(gpointer object,QofParam * getter)908 int64_to_string (gpointer object, QofParam * getter)
909 {
910 	gint64 num =
911 		((query_int64_getter) getter->param_getfcn) (object, getter);
912 
913 	return g_strdup_printf ("%" G_GINT64_FORMAT, num);
914 }
915 
916 /* ================================================================ */
917 /* QOF_TYPE_DOUBLE */
918 
919 static int
double_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)920 double_match_predicate (gpointer object, QofParam * getter,
921 	QofQueryPredData * pd)
922 {
923 	double val;
924 	query_double_t pdata = (query_double_t) pd;
925 
926 	VERIFY_PREDICATE (query_double_type);
927 
928 	val = ((query_double_getter) getter->param_getfcn) (object, getter);
929 
930 	switch (pd->how)
931 	{
932 	case QOF_COMPARE_LT:
933 		return (val < pdata->val);
934 	case QOF_COMPARE_LTE:
935 		return (val <= pdata->val);
936 	case QOF_COMPARE_EQUAL:
937 		return (val == pdata->val);
938 	case QOF_COMPARE_GT:
939 		return (val > pdata->val);
940 	case QOF_COMPARE_GTE:
941 		return (val >= pdata->val);
942 	case QOF_COMPARE_NEQ:
943 		return (val != pdata->val);
944 	default:
945 		PWARN ("bad match type: %d", pd->how);
946 		return 0;
947 	}
948 }
949 
950 static int
double_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)951 double_compare_func (gpointer a, gpointer b,
952 	gint options __attribute__ ((unused)), QofParam * getter)
953 {
954 	double v1, v2;
955 	g_return_val_if_fail (a && b && getter
956 		&& getter->param_getfcn, COMPARE_ERROR);
957 
958 	v1 = ((query_double_getter) getter->param_getfcn) (a, getter);
959 	v2 = ((query_double_getter) getter->param_getfcn) (b, getter);
960 
961 	if (v1 < v2)
962 		return -1;
963 	if (v1 > v2)
964 		return 1;
965 	return 0;
966 }
967 
968 static void
double_free_pdata(QofQueryPredData * pd)969 double_free_pdata (QofQueryPredData * pd)
970 {
971 	query_double_t pdata = (query_double_t) pd;
972 	VERIFY_PDATA (query_double_type);
973 	g_free (pdata);
974 }
975 
976 static QofQueryPredData *
double_copy_predicate(QofQueryPredData * pd)977 double_copy_predicate (QofQueryPredData * pd)
978 {
979 	query_double_t pdata = (query_double_t) pd;
980 	VERIFY_PDATA_R (query_double_type);
981 	return qof_query_double_predicate (pd->how, pdata->val);
982 }
983 
984 static gboolean
double_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)985 double_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
986 {
987 	query_double_t pd1 = (query_double_t) p1;
988 	query_double_t pd2 = (query_double_t) p2;
989 
990 	return (pd1->val == pd2->val);
991 }
992 
993 QofQueryPredData *
qof_query_double_predicate(QofQueryCompare how,double val)994 qof_query_double_predicate (QofQueryCompare how, double val)
995 {
996 	query_double_t pdata = g_new0 (query_double_def, 1);
997 	pdata->pd.type_name = query_double_type;
998 	pdata->pd.how = how;
999 	pdata->val = val;
1000 	return ((QofQueryPredData *) pdata);
1001 }
1002 
1003 static char *
double_to_string(gpointer object,QofParam * getter)1004 double_to_string (gpointer object, QofParam * getter)
1005 {
1006 	double num =
1007 		((query_double_getter) getter->param_getfcn) (object, getter);
1008 
1009 	return g_strdup_printf ("%f", num);
1010 }
1011 
1012 /* QOF_TYPE_BOOLEAN =================================================== */
1013 
1014 static int
boolean_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1015 boolean_match_predicate (gpointer object, QofParam * getter,
1016 	QofQueryPredData * pd)
1017 {
1018 	gboolean val;
1019 	query_boolean_t pdata = (query_boolean_t) pd;
1020 
1021 	VERIFY_PREDICATE (query_boolean_type);
1022 
1023 	val = ((query_boolean_getter) getter->param_getfcn) (object, getter);
1024 
1025 	switch (pd->how)
1026 	{
1027 	case QOF_COMPARE_EQUAL:
1028 		return (val == pdata->val);
1029 	case QOF_COMPARE_NEQ:
1030 		return (val != pdata->val);
1031 	default:
1032 		PWARN ("bad match type: %d", pd->how);
1033 		return 0;
1034 	}
1035 }
1036 
1037 static int
boolean_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1038 boolean_compare_func (gpointer a, gpointer b,
1039 	gint options __attribute__ ((unused)), QofParam * getter)
1040 {
1041 	gboolean va, vb;
1042 	g_return_val_if_fail (a && b && getter
1043 		&& getter->param_getfcn, COMPARE_ERROR);
1044 	va = ((query_boolean_getter) getter->param_getfcn) (a, getter);
1045 	vb = ((query_boolean_getter) getter->param_getfcn) (b, getter);
1046 	if (!va && vb)
1047 		return -1;
1048 	if (va && !vb)
1049 		return 1;
1050 	return 0;
1051 }
1052 
1053 static void
boolean_free_pdata(QofQueryPredData * pd)1054 boolean_free_pdata (QofQueryPredData * pd)
1055 {
1056 	query_boolean_t pdata = (query_boolean_t) pd;
1057 	VERIFY_PDATA (query_boolean_type);
1058 	g_free (pdata);
1059 }
1060 
1061 static QofQueryPredData *
boolean_copy_predicate(QofQueryPredData * pd)1062 boolean_copy_predicate (QofQueryPredData * pd)
1063 {
1064 	query_boolean_t pdata = (query_boolean_t) pd;
1065 	VERIFY_PDATA_R (query_boolean_type);
1066 	return qof_query_boolean_predicate (pd->how, pdata->val);
1067 }
1068 
1069 static gboolean
boolean_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1070 boolean_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1071 {
1072 	query_boolean_t pd1 = (query_boolean_t) p1;
1073 	query_boolean_t pd2 = (query_boolean_t) p2;
1074 
1075 	return (pd1->val == pd2->val);
1076 }
1077 
1078 QofQueryPredData *
qof_query_boolean_predicate(QofQueryCompare how,gboolean val)1079 qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
1080 {
1081 	query_boolean_t pdata;
1082 	g_return_val_if_fail (how == QOF_COMPARE_EQUAL
1083 		|| how == QOF_COMPARE_NEQ, NULL);
1084 
1085 	pdata = g_new0 (query_boolean_def, 1);
1086 	pdata->pd.type_name = query_boolean_type;
1087 	pdata->pd.how = how;
1088 	pdata->val = val;
1089 	return ((QofQueryPredData *) pdata);
1090 }
1091 
1092 static char *
boolean_to_string(gpointer object,QofParam * getter)1093 boolean_to_string (gpointer object, QofParam * getter)
1094 {
1095 	gboolean num =
1096 		((query_boolean_getter) getter->param_getfcn) (object, getter);
1097 
1098 	return g_strdup_printf ("%s", (num ? "X" : ""));
1099 }
1100 
1101 /* QOF_TYPE_CHAR =================================================== */
1102 
1103 static int
char_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1104 char_match_predicate (gpointer object, QofParam * getter,
1105 	QofQueryPredData * pd)
1106 {
1107 	char c;
1108 	query_char_t pdata = (query_char_t) pd;
1109 
1110 	VERIFY_PREDICATE (query_char_type);
1111 
1112 	c = ((query_char_getter) getter->param_getfcn) (object, getter);
1113 
1114 	switch (pdata->options)
1115 	{
1116 	case QOF_CHAR_MATCH_ANY:
1117 		if (strchr (pdata->char_list, c))
1118 			return 1;
1119 		return 0;
1120 	case QOF_CHAR_MATCH_NONE:
1121 		if (!strchr (pdata->char_list, c))
1122 			return 1;
1123 		return 0;
1124 	default:
1125 		PWARN ("bad match type");
1126 		return 0;
1127 	}
1128 }
1129 
1130 static int
char_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1131 char_compare_func (gpointer a, gpointer b,
1132 	gint options __attribute__ ((unused)), QofParam * getter)
1133 {
1134 	char va, vb;
1135 	g_return_val_if_fail (a && b && getter
1136 		&& getter->param_getfcn, COMPARE_ERROR);
1137 	va = ((query_char_getter) getter->param_getfcn) (a, getter);
1138 	vb = ((query_char_getter) getter->param_getfcn) (b, getter);
1139 	return (va - vb);
1140 }
1141 
1142 static void
char_free_pdata(QofQueryPredData * pd)1143 char_free_pdata (QofQueryPredData * pd)
1144 {
1145 	query_char_t pdata = (query_char_t) pd;
1146 	VERIFY_PDATA (query_char_type);
1147 	g_free (pdata->char_list);
1148 	g_free (pdata);
1149 }
1150 
1151 static QofQueryPredData *
char_copy_predicate(QofQueryPredData * pd)1152 char_copy_predicate (QofQueryPredData * pd)
1153 {
1154 	query_char_t pdata = (query_char_t) pd;
1155 	VERIFY_PDATA_R (query_char_type);
1156 	return qof_query_char_predicate (pdata->options, pdata->char_list);
1157 }
1158 
1159 static gboolean
char_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1160 char_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1161 {
1162 	query_char_t pd1 = (query_char_t) p1;
1163 	query_char_t pd2 = (query_char_t) p2;
1164 
1165 	if (pd1->options != pd2->options)
1166 		return FALSE;
1167 	return (safe_strcmp (pd1->char_list, pd2->char_list) == 0);
1168 }
1169 
1170 QofQueryPredData *
qof_query_char_predicate(QofCharMatch options,const char * chars)1171 qof_query_char_predicate (QofCharMatch options, const char *chars)
1172 {
1173 	query_char_t pdata;
1174 	g_return_val_if_fail (chars, NULL);
1175 	pdata = g_new0 (query_char_def, 1);
1176 	pdata->pd.type_name = query_char_type;
1177 	pdata->pd.how = QOF_COMPARE_EQUAL;
1178 	pdata->options = options;
1179 	pdata->char_list = g_strdup (chars);
1180 	return ((QofQueryPredData *) pdata);
1181 }
1182 
1183 static char *
char_to_string(gpointer object,QofParam * getter)1184 char_to_string (gpointer object, QofParam * getter)
1185 {
1186 	char num = ((query_char_getter) getter->param_getfcn) (object, getter);
1187 
1188 	return g_strdup_printf ("%c", num);
1189 }
1190 
1191 /* QOF_TYPE_KVP ================================================ */
1192 
1193 static int
kvp_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1194 kvp_match_predicate (gpointer object, QofParam * getter,
1195 	QofQueryPredData * pd)
1196 {
1197 	int compare;
1198 	KvpFrame *kvp;
1199 	KvpValue *value;
1200 	query_kvp_t pdata = (query_kvp_t) pd;
1201 
1202 	VERIFY_PREDICATE (query_kvp_type);
1203 
1204 	kvp = ((query_kvp_getter) getter->param_getfcn) (object, getter);
1205 	if (!kvp)
1206 		return 0;
1207 
1208 	value = kvp_frame_get_slot_path_gslist (kvp, pdata->path);
1209 	if (!value)
1210 		return 0;
1211 
1212 	if (kvp_value_get_type (value) != kvp_value_get_type (pdata->value))
1213 		return 0;
1214 
1215 	compare = kvp_value_compare (value, pdata->value);
1216 
1217 	switch (pd->how)
1218 	{
1219 	case QOF_COMPARE_LT:
1220 		return (compare < 0);
1221 	case QOF_COMPARE_LTE:
1222 		return (compare <= 0);
1223 	case QOF_COMPARE_EQUAL:
1224 		return (compare == 0);
1225 	case QOF_COMPARE_GTE:
1226 		return (compare >= 0);
1227 	case QOF_COMPARE_GT:
1228 		return (compare > 0);
1229 	case QOF_COMPARE_NEQ:
1230 		return (compare != 0);
1231 	default:
1232 		PWARN ("bad match type: %d", pd->how);
1233 		return 0;
1234 	}
1235 }
1236 
1237 static void
kvp_free_pdata(QofQueryPredData * pd)1238 kvp_free_pdata (QofQueryPredData * pd)
1239 {
1240 	query_kvp_t pdata = (query_kvp_t) pd;
1241 	GSList *node;
1242 
1243 	VERIFY_PDATA (query_kvp_type);
1244 	kvp_value_delete (pdata->value);
1245 	for (node = pdata->path; node; node = node->next)
1246 	{
1247 		g_free (node->data);
1248 		node->data = NULL;
1249 	}
1250 	g_slist_free (pdata->path);
1251 	g_free (pdata);
1252 }
1253 
1254 static QofQueryPredData *
kvp_copy_predicate(QofQueryPredData * pd)1255 kvp_copy_predicate (QofQueryPredData * pd)
1256 {
1257 	query_kvp_t pdata = (query_kvp_t) pd;
1258 	VERIFY_PDATA_R (query_kvp_type);
1259 	return qof_query_kvp_predicate (pd->how, pdata->path, pdata->value);
1260 }
1261 
1262 static gboolean
kvp_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1263 kvp_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1264 {
1265 	query_kvp_t pd1 = (query_kvp_t) p1;
1266 	query_kvp_t pd2 = (query_kvp_t) p2;
1267 	GSList *n1, *n2;
1268 
1269 	n1 = pd1->path;
1270 	n2 = pd2->path;
1271 
1272 	for (; n1 && n2; n1 = n1->next, n2 = n2->next)
1273 	{
1274 		if (safe_strcmp (n1->data, n2->data) != 0)
1275 			return FALSE;
1276 	}
1277 
1278 	if (n1 || n2)
1279 		return FALSE;
1280 
1281 	return (kvp_value_compare (pd1->value, pd2->value) == 0);
1282 }
1283 
1284 QofQueryPredData *
qof_query_kvp_predicate(QofQueryCompare how,GSList * path,const KvpValue * value)1285 qof_query_kvp_predicate (QofQueryCompare how,
1286 	GSList * path, const KvpValue * value)
1287 {
1288 	query_kvp_t pdata;
1289 	GSList *node;
1290 
1291 	g_return_val_if_fail (path && value, NULL);
1292 
1293 	pdata = g_new0 (query_kvp_def, 1);
1294 	pdata->pd.type_name = query_kvp_type;
1295 	pdata->pd.how = how;
1296 	pdata->value = kvp_value_copy (value);
1297 	pdata->path = g_slist_copy (path);
1298 	for (node = pdata->path; node; node = node->next)
1299 		node->data = g_strdup (node->data);
1300 
1301 	return ((QofQueryPredData *) pdata);
1302 }
1303 
1304 QofQueryPredData *
qof_query_kvp_predicate_path(QofQueryCompare how,const char * path,const KvpValue * value)1305 qof_query_kvp_predicate_path (QofQueryCompare how,
1306 	const char *path, const KvpValue * value)
1307 {
1308 	QofQueryPredData *pd;
1309 	GSList *spath = NULL;
1310 	char *str, *p;
1311 
1312 	if (!path)
1313 		return NULL;
1314 
1315 	str = g_strdup (path);
1316 	p = str;
1317 	if (0 == *p)
1318 		return NULL;
1319 	if ('/' == *p)
1320 		p++;
1321 
1322 	while (p)
1323 	{
1324 		spath = g_slist_append (spath, p);
1325 		p = strchr (p, '/');
1326 		if (p)
1327 		{
1328 			*p = 0;
1329 			p++;
1330 		}
1331 	}
1332 
1333 	pd = qof_query_kvp_predicate (how, spath, value);
1334 	g_free (str);
1335 	return pd;
1336 }
1337 
1338 
1339 /* QOF_TYPE_COLLECT =============================================== */
1340 
1341 static int
collect_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1342 collect_match_predicate (gpointer object, QofParam * getter,
1343 	QofQueryPredData * pd)
1344 {
1345 	query_coll_t pdata;
1346 	QofCollection * G_GNUC_UNUSED coll;
1347 	GList *node, *node2, *o_list;
1348 	const GUID *guid;
1349 
1350 	pdata = (query_coll_t) pd;
1351 	VERIFY_PREDICATE (query_collect_type);
1352 	coll = ((query_collect_getter) getter->param_getfcn) (object, getter);
1353 	guid = NULL;
1354 	switch (pdata->options)
1355 	{
1356 	case QOF_GUID_MATCH_ALL:
1357 		{
1358 			for (node = pdata->guids; node; node = node->next)
1359 			{
1360 				for (o_list = object; o_list; o_list = o_list->next)
1361 				{
1362 					guid = ((query_guid_getter) getter->param_getfcn)
1363 						(o_list->data, getter);
1364 					if (guid_equal (node->data, guid))
1365 					{
1366 						break;
1367 					}
1368 				}
1369 				if (o_list == NULL)
1370 				{
1371 					break;
1372 				}
1373 			}
1374 			break;
1375 		}
1376 	case QOF_GUID_MATCH_LIST_ANY:
1377 		{
1378 			o_list =
1379 				((query_glist_getter) getter->param_getfcn) (object,
1380 				getter);
1381 			for (node = o_list; node; node = node->next)
1382 			{
1383 				for (node2 = pdata->guids; node2; node2 = node2->next)
1384 				{
1385 					if (guid_equal (node->data, node2->data))
1386 					{
1387 						break;
1388 					}
1389 				}
1390 				if (node2 != NULL)
1391 				{
1392 					break;
1393 				}
1394 			}
1395 			g_list_free (o_list);
1396 			break;
1397 		}
1398 	default:
1399 		{
1400 			guid =
1401 				((query_guid_getter) getter->param_getfcn) (object,
1402 				getter);
1403 			for (node = pdata->guids; node; node = node->next)
1404 			{
1405 				if (guid_equal (node->data, guid))
1406 				{
1407 					break;
1408 				}
1409 			}
1410 		}
1411 		switch (pdata->options)
1412 		{
1413 		case QOF_GUID_MATCH_ANY:
1414 		case QOF_GUID_MATCH_LIST_ANY:
1415 			{
1416 				return (node != NULL);
1417 				break;
1418 			}
1419 		case QOF_GUID_MATCH_NONE:
1420 		case QOF_GUID_MATCH_ALL:
1421 			{
1422 				return (node == NULL);
1423 				break;
1424 			}
1425 		case QOF_GUID_MATCH_NULL:
1426 			{
1427 				return (guid == NULL);
1428 				break;
1429 			}
1430 		default:
1431 			{
1432 				PWARN ("bad match type");
1433 				return 0;
1434 			}
1435 		}
1436 	}
1437 	return 0;
1438 }
1439 
1440 static int
collect_compare_func(gpointer a,gpointer b,gint options,QofParam * getter)1441 collect_compare_func (gpointer a, gpointer b,
1442 	gint options __attribute__ ((unused)),
1443 	QofParam * getter)
1444 {
1445 	gint result;
1446 	QofCollection *c1, *c2;
1447 
1448 	c1 = ((query_collect_getter) getter->param_getfcn) (a, getter);
1449 	c2 = ((query_collect_getter) getter->param_getfcn) (b, getter);
1450 	result = qof_collection_compare (c1, c2);
1451 	return result;
1452 }
1453 
1454 static void
collect_free_pdata(QofQueryPredData * pd)1455 collect_free_pdata (QofQueryPredData * pd)
1456 {
1457 	query_coll_t pdata;
1458 	GList *node;
1459 
1460 	node = NULL;
1461 	pdata = (query_coll_t) pd;
1462 	VERIFY_PDATA (query_collect_type);
1463 	for (node = pdata->guids; node; node = node->next)
1464 	{
1465 		guid_free (node->data);
1466 	}
1467 	qof_collection_destroy (pdata->coll);
1468 	g_list_free (pdata->guids);
1469 	g_free (pdata);
1470 }
1471 
1472 static QofQueryPredData *
collect_copy_predicate(QofQueryPredData * pd)1473 collect_copy_predicate (QofQueryPredData * pd)
1474 {
1475 	query_coll_t pdata = (query_coll_t) pd;
1476 
1477 	VERIFY_PDATA_R (query_collect_type);
1478 	return qof_query_collect_predicate (pdata->options, pdata->coll);
1479 }
1480 
1481 static gboolean
collect_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1482 collect_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1483 {
1484 	query_coll_t pd1;
1485 	query_coll_t pd2;
1486 	gint result;
1487 
1488 	pd1 = (query_coll_t) p1;
1489 	pd2 = (query_coll_t) p2;
1490 	result = qof_collection_compare (pd1->coll, pd2->coll);
1491 	if (result == 0)
1492 	{
1493 		return TRUE;
1494 	}
1495 	return FALSE;
1496 }
1497 
1498 static void
query_collect_cb(QofEntity * ent,gpointer user_data)1499 query_collect_cb (QofEntity * ent, gpointer user_data)
1500 {
1501 	query_coll_t pdata;
1502 	GUID *guid;
1503 
1504 	guid = guid_malloc ();
1505 	guid = (GUID *) qof_entity_get_guid (ent);
1506 	pdata = (query_coll_t) user_data;
1507 	pdata->guids = g_list_append (pdata->guids, guid);
1508 }
1509 
1510 QofQueryPredData *
qof_query_collect_predicate(QofGuidMatch options,QofCollection * coll)1511 qof_query_collect_predicate (QofGuidMatch options, QofCollection * coll)
1512 {
1513 	query_coll_t pdata;
1514 
1515 	g_return_val_if_fail (coll, NULL);
1516 	pdata = g_new0 (query_coll_def, 1);
1517 	pdata->pd.type_name = query_collect_type;
1518 	pdata->options = options;
1519 	qof_collection_foreach (coll, query_collect_cb, pdata);
1520 	if (NULL == pdata->guids)
1521 	{
1522 		return NULL;
1523 	}
1524 	return ((QofQueryPredData *) pdata);
1525 }
1526 
1527 /* QOF_TYPE_CHOICE */
1528 
1529 static int
choice_match_predicate(gpointer object,QofParam * getter,QofQueryPredData * pd)1530 choice_match_predicate (gpointer object, QofParam * getter,
1531 	QofQueryPredData * pd)
1532 {
1533 	query_choice_t pdata = (query_choice_t) pd;
1534 	GList *node, *o_list;
1535 	const GUID *guid = NULL;
1536 
1537 	VERIFY_PREDICATE (query_choice_type);
1538 
1539 	switch (pdata->options)
1540 	{
1541 
1542 	case QOF_GUID_MATCH_ALL:
1543 		/* object is a GList of objects; param_getfcn must be called on each one.
1544 		 * See if every guid in the predicate is accounted-for in the
1545 		 * object list
1546 		 */
1547 
1548 		for (node = pdata->guids; node; node = node->next)
1549 		{
1550 			/* See if this GUID matches the object's guid */
1551 			for (o_list = object; o_list; o_list = o_list->next)
1552 			{
1553 				guid =
1554 					((query_choice_getter) getter->param_getfcn) (o_list->
1555 					data, getter);
1556 				if (guid_equal (node->data, guid))
1557 					break;
1558 			}
1559 
1560 			/*
1561 			 * If o_list is NULL, we've walked the whole list without finding
1562 			 * a match.  Therefore break out now, the match has failed.
1563 			 */
1564 			if (o_list == NULL)
1565 				break;
1566 		}
1567 
1568 		/*
1569 		 * The match is complete.  If node == NULL then we've succesfully
1570 		 * found a match for all the guids in the predicate.  Return
1571 		 * appropriately below.
1572 		 */
1573 
1574 		break;
1575 
1576 	case QOF_GUID_MATCH_LIST_ANY:
1577 
1578 		o_list =
1579 			((query_glist_getter) getter->param_getfcn) (object, getter);
1580 
1581 		for (node = o_list; node; node = node->next)
1582 		{
1583 			GList *node2;
1584 
1585 			for (node2 = pdata->guids; node2; node2 = node2->next)
1586 			{
1587 				if (guid_equal (node->data, node2->data))
1588 					break;
1589 			}
1590 
1591 			if (node2 != NULL)
1592 				break;
1593 		}
1594 
1595 		g_list_free (o_list);
1596 
1597 		break;
1598 
1599 	default:
1600 		/* object is a single object, getter returns a GUID*
1601 		 *
1602 		 * See if the guid is in the list
1603 		 */
1604 
1605 		guid =
1606 			((query_choice_getter) getter->param_getfcn) (object, getter);
1607 		for (node = pdata->guids; node; node = node->next)
1608 		{
1609 			if (guid_equal (node->data, guid))
1610 				break;
1611 		}
1612 	}
1613 
1614 	switch (pdata->options)
1615 	{
1616 	case QOF_GUID_MATCH_ANY:
1617 	case QOF_GUID_MATCH_LIST_ANY:
1618 		return (node != NULL);
1619 		break;
1620 	case QOF_GUID_MATCH_NONE:
1621 	case QOF_GUID_MATCH_ALL:
1622 		return (node == NULL);
1623 		break;
1624 	case QOF_GUID_MATCH_NULL:
1625 		return (guid == NULL);
1626 		break;
1627 	default:
1628 		PWARN ("bad match type");
1629 		return 0;
1630 	}
1631 }
1632 
1633 static void
choice_free_pdata(QofQueryPredData * pd)1634 choice_free_pdata (QofQueryPredData * pd)
1635 {
1636 	query_choice_t pdata = (query_choice_t) pd;
1637 	GList *node;
1638 	VERIFY_PDATA (query_choice_type);
1639 	for (node = pdata->guids; node; node = node->next)
1640 	{
1641 		guid_free (node->data);
1642 	}
1643 	g_list_free (pdata->guids);
1644 	g_free (pdata);
1645 }
1646 
1647 static QofQueryPredData *
choice_copy_predicate(QofQueryPredData * pd)1648 choice_copy_predicate (QofQueryPredData * pd)
1649 {
1650 	query_choice_t pdata = (query_choice_t) pd;
1651 	VERIFY_PDATA_R (query_choice_type);
1652 	return qof_query_choice_predicate (pdata->options, pdata->guids);
1653 }
1654 
1655 static gboolean
choice_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1656 choice_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2)
1657 {
1658 	query_choice_t pd1 = (query_choice_t) p1;
1659 	query_choice_t pd2 = (query_choice_t) p2;
1660 	GList *l1 = pd1->guids, *l2 = pd2->guids;
1661 
1662 	if (pd1->options != pd2->options)
1663 		return FALSE;
1664 	if (g_list_length (l1) != g_list_length (l2))
1665 		return FALSE;
1666 	for (; l1; l1 = l1->next, l2 = l2->next)
1667 	{
1668 		if (!guid_equal (l1->data, l2->data))
1669 			return FALSE;
1670 	}
1671 	return TRUE;
1672 }
1673 
1674 QofQueryPredData *
qof_query_choice_predicate(QofGuidMatch options,GList * guid_list)1675 qof_query_choice_predicate (QofGuidMatch options, GList * guid_list)
1676 {
1677 	query_choice_t pdata;
1678 	GList *node;
1679 
1680 	if (NULL == guid_list)
1681 		return NULL;
1682 
1683 	pdata = g_new0 (query_choice_def, 1);
1684 	pdata->pd.how = QOF_COMPARE_EQUAL;
1685 	pdata->pd.type_name = query_choice_type;
1686 	pdata->options = options;
1687 
1688 	pdata->guids = g_list_copy (guid_list);
1689 	for (node = pdata->guids; node; node = node->next)
1690 	{
1691 		GUID *guid = guid_malloc ();
1692 		*guid = *((GUID *) node->data);
1693 		node->data = guid;
1694 	}
1695 	return ((QofQueryPredData *) pdata);
1696 }
1697 
1698 
1699 /* initialization ================================================== */
1700 /** This function registers a new Core Object with the QofQuery
1701  * subsystem.  It maps the "core_name" object to the given
1702  * query_predicate, predicate_copy, and predicate_data_free functions.
1703  *
1704  * An example:
1705  * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
1706  *                               string_compare_fcn, string_free_pdata,
1707  *                               string_print_fcn, pred_equal_fcn);
1708  */
1709 
1710 
1711 static void
qof_query_register_core_object(QofType core_name,QofQueryPredicateFunc pred,QofCompareFunc comp,QueryPredicateCopyFunc copy,QueryPredDataFree pd_free,QueryToString toString,QueryPredicateEqual pred_equal)1712 qof_query_register_core_object (QofType core_name,
1713 	QofQueryPredicateFunc pred,
1714 	QofCompareFunc comp,
1715 	QueryPredicateCopyFunc copy,
1716 	QueryPredDataFree pd_free,
1717 	QueryToString toString, QueryPredicateEqual pred_equal)
1718 {
1719 	g_return_if_fail (core_name);
1720 	g_return_if_fail (*core_name != '\0');
1721 
1722 	if (pred)
1723 		g_hash_table_insert (predTable, (char *) core_name, pred);
1724 
1725 	if (comp)
1726 		g_hash_table_insert (cmpTable, (char *) core_name, comp);
1727 
1728 	if (copy)
1729 		g_hash_table_insert (copyTable, (char *) core_name, copy);
1730 
1731 	if (pd_free)
1732 		g_hash_table_insert (freeTable, (char *) core_name, pd_free);
1733 
1734 	if (toString)
1735 		g_hash_table_insert (toStringTable, (char *) core_name, toString);
1736 
1737 	if (pred_equal)
1738 		g_hash_table_insert (predEqualTable, (char *) core_name,
1739 			pred_equal);
1740 }
1741 
1742 static void
init_tables(void)1743 init_tables (void)
1744 {
1745 	guint i;
1746 	struct
1747 	{
1748 		QofType name;
1749 		QofQueryPredicateFunc pred;
1750 		QofCompareFunc comp;
1751 		QueryPredicateCopyFunc copy;
1752 		QueryPredDataFree pd_free;
1753 		QueryToString toString;
1754 		QueryPredicateEqual pred_equal;
1755 	} knownTypes[] =
1756 	{
1757 		{
1758 		QOF_TYPE_STRING, string_match_predicate, string_compare_func,
1759 				string_copy_predicate, string_free_pdata,
1760 				string_to_string, string_predicate_equal},
1761 		{
1762 		QOF_TYPE_TIME, time_match_predicate, time_compare_func,
1763 				time_copy_predicate, time_free_pdata, time_to_string,
1764 				time_predicate_equal},
1765 		{
1766 		QOF_TYPE_DEBCRED, numeric_match_predicate,
1767 				numeric_compare_func, numeric_copy_predicate,
1768 				numeric_free_pdata, debcred_to_string,
1769 				numeric_predicate_equal},
1770 		{
1771 		QOF_TYPE_NUMERIC, numeric_match_predicate,
1772 				numeric_compare_func, numeric_copy_predicate,
1773 				numeric_free_pdata, numeric_to_string,
1774 				numeric_predicate_equal},
1775 		{
1776 		QOF_TYPE_GUID, guid_match_predicate, NULL,
1777 				guid_copy_predicate, guid_free_pdata, NULL,
1778 				guid_predicate_equal},
1779 		{
1780 		QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
1781 				int32_copy_predicate, int32_free_pdata,
1782 				int32_to_string, int32_predicate_equal},
1783 		{
1784 		QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
1785 				int64_copy_predicate, int64_free_pdata,
1786 				int64_to_string, int64_predicate_equal},
1787 		{
1788 		QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
1789 				double_copy_predicate, double_free_pdata,
1790 				double_to_string, double_predicate_equal},
1791 		{
1792 		QOF_TYPE_BOOLEAN, boolean_match_predicate,
1793 				boolean_compare_func, boolean_copy_predicate,
1794 				boolean_free_pdata, boolean_to_string,
1795 				boolean_predicate_equal},
1796 		{
1797 		QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
1798 				char_copy_predicate, char_free_pdata, char_to_string,
1799 				char_predicate_equal},
1800 		{
1801 		QOF_TYPE_KVP, kvp_match_predicate, NULL, kvp_copy_predicate,
1802 				kvp_free_pdata, NULL, kvp_predicate_equal},
1803 		{
1804 		QOF_TYPE_COLLECT, collect_match_predicate,
1805 				collect_compare_func, collect_copy_predicate,
1806 				collect_free_pdata, NULL, collect_predicate_equal},
1807 		{
1808 	QOF_TYPE_CHOICE, choice_match_predicate, NULL,
1809 				choice_copy_predicate, choice_free_pdata, NULL,
1810 				choice_predicate_equal},};
1811 
1812 	/* Register the known data types */
1813 	for (i = 0; i < (sizeof (knownTypes) / sizeof (*knownTypes)); i++)
1814 	{
1815 		qof_query_register_core_object (knownTypes[i].name,
1816 			knownTypes[i].pred,
1817 			knownTypes[i].comp,
1818 			knownTypes[i].copy,
1819 			knownTypes[i].pd_free,
1820 			knownTypes[i].toString, knownTypes[i].pred_equal);
1821 	}
1822 }
1823 
1824 static QueryPredicateCopyFunc
qof_query_copy_predicate(QofType type)1825 qof_query_copy_predicate (QofType type)
1826 {
1827 	QueryPredicateCopyFunc rc;
1828 	g_return_val_if_fail (type, NULL);
1829 	rc = g_hash_table_lookup (copyTable, type);
1830 	return rc;
1831 }
1832 
1833 static QueryPredDataFree
qof_query_predicate_free(QofType type)1834 qof_query_predicate_free (QofType type)
1835 {
1836 	g_return_val_if_fail (type, NULL);
1837 	return g_hash_table_lookup (freeTable, type);
1838 }
1839 
1840 /********************************************************************/
1841 /* PUBLISHED API FUNCTIONS */
1842 
1843 void
qof_query_core_init(void)1844 qof_query_core_init (void)
1845 {
1846 	/* Only let us initialize once */
1847 	if (initialized)
1848 		return;
1849 	initialized = TRUE;
1850 
1851 	/* Create the tables */
1852 	predTable = g_hash_table_new (g_str_hash, g_str_equal);
1853 	cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
1854 	copyTable = g_hash_table_new (g_str_hash, g_str_equal);
1855 	freeTable = g_hash_table_new (g_str_hash, g_str_equal);
1856 	toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
1857 	predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
1858 
1859 	init_tables ();
1860 }
1861 
1862 void
qof_query_core_shutdown(void)1863 qof_query_core_shutdown (void)
1864 {
1865 	if (!initialized)
1866 		return;
1867 	initialized = FALSE;
1868 
1869 	g_hash_table_destroy (predTable);
1870 	g_hash_table_destroy (cmpTable);
1871 	g_hash_table_destroy (copyTable);
1872 	g_hash_table_destroy (freeTable);
1873 	g_hash_table_destroy (toStringTable);
1874 	g_hash_table_destroy (predEqualTable);
1875 }
1876 
1877 QofQueryPredicateFunc
qof_query_core_get_predicate(QofType type)1878 qof_query_core_get_predicate (QofType type)
1879 {
1880 	g_return_val_if_fail (type, NULL);
1881 	return g_hash_table_lookup (predTable, type);
1882 }
1883 
1884 QofCompareFunc
qof_query_core_get_compare(QofType type)1885 qof_query_core_get_compare (QofType type)
1886 {
1887 	g_return_val_if_fail (type, NULL);
1888 	return g_hash_table_lookup (cmpTable, type);
1889 }
1890 
1891 void
qof_query_core_predicate_free(QofQueryPredData * pdata)1892 qof_query_core_predicate_free (QofQueryPredData * pdata)
1893 {
1894 	QueryPredDataFree free_fcn;
1895 
1896 	g_return_if_fail (pdata);
1897 	g_return_if_fail (pdata->type_name);
1898 
1899 	free_fcn = qof_query_predicate_free (pdata->type_name);
1900 	free_fcn (pdata);
1901 }
1902 
1903 QofQueryPredData *
qof_query_core_predicate_copy(QofQueryPredData * pdata)1904 qof_query_core_predicate_copy (QofQueryPredData * pdata)
1905 {
1906 	QueryPredicateCopyFunc copy;
1907 
1908 	g_return_val_if_fail (pdata, NULL);
1909 	g_return_val_if_fail (pdata->type_name, NULL);
1910 
1911 	copy = qof_query_copy_predicate (pdata->type_name);
1912 	return (copy (pdata));
1913 }
1914 
1915 gchar *
qof_query_core_to_string(QofType type,gpointer object,QofParam * getter)1916 qof_query_core_to_string (QofType type, gpointer object,
1917 						  QofParam * getter)
1918 {
1919 	QueryToString toString;
1920 
1921 	g_return_val_if_fail (type, NULL);
1922 	g_return_val_if_fail (object, NULL);
1923 	g_return_val_if_fail (getter, NULL);
1924 
1925 	toString = g_hash_table_lookup (toStringTable, type);
1926 	g_return_val_if_fail (toString, NULL);
1927 
1928 	return toString (object, getter);
1929 }
1930 
1931 gboolean
qof_query_core_predicate_equal(QofQueryPredData * p1,QofQueryPredData * p2)1932 qof_query_core_predicate_equal (QofQueryPredData * p1,
1933 	QofQueryPredData * p2)
1934 {
1935 	QueryPredicateEqual pred_equal;
1936 
1937 	if (p1 == p2)
1938 		return TRUE;
1939 	if (!p1 || !p2)
1940 		return FALSE;
1941 
1942 	if (p1->how != p2->how)
1943 		return FALSE;
1944 	if (safe_strcmp (p1->type_name, p2->type_name))
1945 		return FALSE;
1946 
1947 	pred_equal = g_hash_table_lookup (predEqualTable, p1->type_name);
1948 	g_return_val_if_fail (pred_equal, FALSE);
1949 
1950 	return pred_equal (p1, p2);
1951 }
1952