QOF
0.8.7
|
00001 /********************************************************************\ 00002 * QueryCore.c -- API for providing core Query data types * 00003 * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> * 00004 * Copyright (C) 2006-2008 Neil Williams <linux@codehelp.co.uk> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 \********************************************************************/ 00024 00025 #include "config.h" 00026 00027 #include <glib.h> 00028 00029 #include "qof.h" 00030 #include "qofquerycore-p.h" 00031 00032 static QofLogModule log_module = QOF_MOD_QUERY; 00033 00034 /* A function to destroy a query predicate's pdata */ 00035 typedef void (*QueryPredDataFree) (QofQueryPredData * pdata); 00036 00037 /* A function to copy a query's predicate data */ 00038 typedef QofQueryPredData *(*QueryPredicateCopyFunc) (QofQueryPredData * 00039 pdata); 00040 00041 /* A function to take the object, apply the getter->param_getfcn, 00042 * and return a printable string. Note that this QofParam->getfnc 00043 * function should be returning a type equal to this core object type. 00044 * 00045 * Note that this string MUST be freed by the caller. 00046 */ 00047 typedef gchar *(*QueryToString) (gpointer object, QofParam * getter); 00048 00049 /* A function to test for equality of predicate data */ 00050 typedef gboolean (*QueryPredicateEqual) (QofQueryPredData * p1, 00051 QofQueryPredData * p2); 00052 00053 static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type); 00054 static QueryPredDataFree qof_query_predicate_free (QofType type); 00055 00056 /* Core Type Predicate helpers */ 00057 typedef const gchar *(*query_string_getter) (gpointer, QofParam *); 00058 static const gchar *query_string_type = QOF_TYPE_STRING; 00059 00060 typedef QofTime *(*query_time_getter) (gpointer, QofParam *); 00061 static const gchar *query_time_type = QOF_TYPE_TIME; 00062 00063 typedef QofNumeric (*query_numeric_getter) (gpointer, QofParam *); 00064 static const gchar *query_numeric_type = QOF_TYPE_NUMERIC; 00065 00066 typedef GList *(*query_glist_getter) (gpointer, QofParam *); 00067 typedef const GUID *(*query_guid_getter) (gpointer, QofParam *); 00068 static const gchar *query_guid_type = QOF_TYPE_GUID; 00069 00070 typedef gint32 (*query_int32_getter) (gpointer, QofParam *); 00071 static const gchar *query_int32_type = QOF_TYPE_INT32; 00072 00073 typedef gint64 (*query_int64_getter) (gpointer, QofParam *); 00074 static const char *query_int64_type = QOF_TYPE_INT64; 00075 00076 typedef double (*query_double_getter) (gpointer, QofParam *); 00077 static const gchar *query_double_type = QOF_TYPE_DOUBLE; 00078 00079 typedef gboolean (*query_boolean_getter) (gpointer, QofParam *); 00080 static const gchar *query_boolean_type = QOF_TYPE_BOOLEAN; 00081 00082 typedef char (*query_char_getter) (gpointer, QofParam *); 00083 static const char *query_char_type = QOF_TYPE_CHAR; 00084 00085 typedef KvpFrame *(*query_kvp_getter) (gpointer, QofParam *); 00086 static const gchar *query_kvp_type = QOF_TYPE_KVP; 00087 00088 typedef QofCollection *(*query_collect_getter) (gpointer, QofParam *); 00089 static const gchar *query_collect_type = QOF_TYPE_COLLECT; 00090 00091 typedef const GUID *(*query_choice_getter) (gpointer, QofParam *); 00092 static const gchar *query_choice_type = QOF_TYPE_CHOICE; 00093 00094 /* Tables for predicate storage and lookup */ 00095 static gboolean initialized = FALSE; 00096 static GHashTable *predTable = NULL; 00097 static GHashTable *cmpTable = NULL; 00098 static GHashTable *copyTable = NULL; 00099 static GHashTable *freeTable = NULL; 00100 static GHashTable *toStringTable = NULL; 00101 static GHashTable *predEqualTable = NULL; 00102 00103 #define COMPARE_ERROR -3 00104 #define PREDICATE_ERROR -2 00105 00106 #define VERIFY_PDATA(str) { \ 00107 g_return_if_fail (pd != NULL); \ 00108 g_return_if_fail (pd->type_name == str || \ 00109 !safe_strcmp (str, pd->type_name)); \ 00110 } 00111 #define VERIFY_PDATA_R(str) { \ 00112 g_return_val_if_fail (pd != NULL, NULL); \ 00113 g_return_val_if_fail (pd->type_name == str || \ 00114 !safe_strcmp (str, pd->type_name), \ 00115 NULL); \ 00116 } 00117 #define VERIFY_PREDICATE(str) { \ 00118 g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \ 00119 g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \ 00120 g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \ 00121 g_return_val_if_fail (pd->type_name == str || \ 00122 !safe_strcmp (str, pd->type_name), \ 00123 PREDICATE_ERROR); \ 00124 } 00125 00126 /* *******************************************************************/ 00127 /* TYPE-HANDLING FUNCTIONS */ 00128 00129 /* QOF_TYPE_STRING */ 00130 00131 static gint 00132 string_match_predicate (gpointer object, 00133 QofParam * getter, QofQueryPredData * pd) 00134 { 00135 query_string_t pdata = (query_string_t) pd; 00136 const gchar *s; 00137 gint ret = 0; 00138 00139 VERIFY_PREDICATE (query_string_type); 00140 00141 s = ((query_string_getter) getter->param_getfcn) (object, getter); 00142 00143 if (!s) 00144 s = ""; 00145 00146 if (pdata->is_regex) 00147 { 00148 regmatch_t match; 00149 if (!regexec (&pdata->compiled, s, 1, &match, 0)) 00150 ret = 1; 00151 00152 } 00153 else if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE) 00154 { 00155 if (strcasestr (s, pdata->matchstring)) 00156 ret = 1; 00157 00158 } 00159 else 00160 { 00161 if (strstr (s, pdata->matchstring)) 00162 ret = 1; 00163 } 00164 00165 switch (pd->how) 00166 { 00167 case QOF_COMPARE_EQUAL: 00168 return ret; 00169 case QOF_COMPARE_NEQ: 00170 return !ret; 00171 default: 00172 PWARN ("bad match type: %d", pd->how); 00173 return 0; 00174 } 00175 } 00176 00177 static gint 00178 string_compare_func (gpointer a, gpointer b, gint options, 00179 QofParam * getter) 00180 { 00181 const gchar *s1, *s2; 00182 g_return_val_if_fail (a && b && getter 00183 && getter->param_getfcn, COMPARE_ERROR); 00184 00185 s1 = ((query_string_getter) getter->param_getfcn) (a, getter); 00186 s2 = ((query_string_getter) getter->param_getfcn) (b, getter); 00187 00188 if (options == QOF_STRING_MATCH_CASEINSENSITIVE) 00189 return safe_strcasecmp (s1, s2); 00190 00191 return safe_strcmp (s1, s2); 00192 } 00193 00194 static void 00195 string_free_pdata (QofQueryPredData * pd) 00196 { 00197 query_string_t pdata = (query_string_t) pd; 00198 00199 VERIFY_PDATA (query_string_type); 00200 00201 if (pdata->is_regex) 00202 regfree (&pdata->compiled); 00203 else 00204 g_free (pdata->matchstring); 00205 00206 g_free (pdata); 00207 } 00208 00209 static QofQueryPredData * 00210 string_copy_predicate (QofQueryPredData * pd) 00211 { 00212 query_string_t pdata = (query_string_t) pd; 00213 00214 VERIFY_PDATA_R (query_string_type); 00215 00216 return qof_query_string_predicate (pd->how, pdata->matchstring, 00217 pdata->options, pdata->is_regex); 00218 } 00219 00220 static gboolean 00221 string_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00222 { 00223 query_string_t pd1 = (query_string_t) p1; 00224 query_string_t pd2 = (query_string_t) p2; 00225 00226 if (pd1->options != pd2->options) 00227 return FALSE; 00228 if (pd1->is_regex != pd2->is_regex) 00229 return FALSE; 00230 return (safe_strcmp (pd1->matchstring, pd2->matchstring) == 0); 00231 } 00232 00233 QofQueryPredData * 00234 qof_query_string_predicate (QofQueryCompare how, 00235 const gchar *str, QofStringMatch options, gboolean is_regex) 00236 { 00237 query_string_t pdata; 00238 00239 g_return_val_if_fail (str, NULL); 00240 g_return_val_if_fail (*str != '\0', NULL); 00241 g_return_val_if_fail (how == QOF_COMPARE_EQUAL 00242 || how == QOF_COMPARE_NEQ, NULL); 00243 00244 pdata = g_new0 (query_string_def, 1); 00245 pdata->pd.type_name = query_string_type; 00246 pdata->pd.how = how; 00247 pdata->options = options; 00248 pdata->matchstring = g_strdup (str); 00249 00250 if (is_regex) 00251 { 00252 int flags = REG_EXTENDED; 00253 if (options == QOF_STRING_MATCH_CASEINSENSITIVE) 00254 flags |= REG_ICASE; 00255 00256 regcomp (&pdata->compiled, str, flags); 00257 pdata->is_regex = TRUE; 00258 } 00259 00260 return ((QofQueryPredData *) pdata); 00261 } 00262 00263 static gchar * 00264 string_to_string (gpointer object, QofParam * getter) 00265 { 00266 const char *res; 00267 res = ((query_string_getter) getter->param_getfcn) (object, getter); 00268 if (res) 00269 return g_strdup (res); 00270 return NULL; 00271 } 00272 00273 /* QOF_TYPE_TIME */ 00274 00275 static gint 00276 time_compare (QofTime *ta, QofTime *tb, QofDateMatch options) 00277 { 00278 if (options == QOF_DATE_MATCH_DAY) 00279 { 00280 qof_time_set_day_start (ta); 00281 qof_time_set_day_start (tb); 00282 } 00283 return qof_time_cmp (ta, tb); 00284 } 00285 00286 static int 00287 time_match_predicate (gpointer object, QofParam * getter, 00288 QofQueryPredData * pd) 00289 { 00290 query_time_t pdata = (query_time_t) pd; 00291 QofTime *objtime; 00292 gint compare; 00293 00294 VERIFY_PREDICATE (query_time_type); 00295 00296 objtime = ((query_time_getter) getter->param_getfcn) (object, getter); 00297 compare = time_compare (objtime, pdata->qt, pdata->options); 00298 00299 switch (pd->how) 00300 { 00301 case QOF_COMPARE_LT: 00302 return (compare < 0); 00303 case QOF_COMPARE_LTE: 00304 return (compare <= 0); 00305 case QOF_COMPARE_EQUAL: 00306 return (compare == 0); 00307 case QOF_COMPARE_GT: 00308 return (compare > 0); 00309 case QOF_COMPARE_GTE: 00310 return (compare >= 0); 00311 case QOF_COMPARE_NEQ: 00312 return (compare != 0); 00313 default: 00314 PWARN ("bad match type: %d", pd->how); 00315 return 0; 00316 } 00317 } 00318 00319 static gint 00320 time_compare_func (gpointer a, gpointer b, gint options, 00321 QofParam * getter) 00322 { 00323 QofTime *ta, *tb; 00324 00325 g_return_val_if_fail (a && b && getter 00326 && getter->param_getfcn, COMPARE_ERROR); 00327 00328 ta = ((query_time_getter) getter->param_getfcn) (a, getter); 00329 tb = ((query_time_getter) getter->param_getfcn) (b, getter); 00330 00331 return time_compare (ta, tb, options); 00332 } 00333 00334 static void 00335 time_free_pdata (QofQueryPredData * pd) 00336 { 00337 query_time_t pdata = (query_time_t) pd; 00338 00339 VERIFY_PDATA (query_time_type); 00340 00341 g_free (pdata); 00342 } 00343 00344 static QofQueryPredData * 00345 time_copy_predicate (QofQueryPredData * pd) 00346 { 00347 query_time_t pdata = (query_time_t) pd; 00348 00349 VERIFY_PDATA_R (query_time_type); 00350 00351 return qof_query_time_predicate (pd->how, pdata->options, 00352 pdata->qt); 00353 } 00354 00355 static gboolean 00356 time_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00357 { 00358 query_time_t pd1 = (query_time_t) p1; 00359 query_time_t pd2 = (query_time_t) p2; 00360 00361 if (pd1->options != pd2->options) 00362 return FALSE; 00363 return qof_time_equal (pd1->qt, pd2->qt); 00364 } 00365 00366 QofQueryPredData * 00367 qof_query_time_predicate (QofQueryCompare how, 00368 QofDateMatch options, QofTime *qt) 00369 { 00370 query_time_t pdata; 00371 00372 pdata = g_new0 (query_time_def, 1); 00373 pdata->pd.type_name = query_time_type; 00374 pdata->pd.how = how; 00375 pdata->options = options; 00376 pdata->qt = qt; 00377 return ((QofQueryPredData *) pdata); 00378 } 00379 00380 gboolean 00381 qof_query_time_predicate_get_time (QofQueryPredData * pd, 00382 QofTime *qt) 00383 { 00384 query_time_t pdata = (query_time_t) pd; 00385 00386 if (pdata->pd.type_name != query_time_type) 00387 return FALSE; 00388 qt = pdata->qt; 00389 return TRUE; 00390 } 00391 00392 static gchar * 00393 time_to_string (gpointer object, QofParam * getter) 00394 { 00395 QofDate *qd; 00396 QofTime *qt = 00397 ((query_time_getter) getter->param_getfcn) (object, getter); 00398 00399 qd = qof_date_from_qtime (qt); 00400 return qof_date_print (qd, QOF_DATE_FORMAT_UTC); 00401 } 00402 00403 /* QOF_TYPE_NUMERIC ================================================= */ 00404 00405 static int 00406 numeric_match_predicate (gpointer object, QofParam * getter, 00407 QofQueryPredData * pd) 00408 { 00409 query_numeric_t pdata = (query_numeric_t) pd; 00410 QofNumeric obj_val; 00411 gint compare; 00412 00413 VERIFY_PREDICATE (query_numeric_type); 00414 00415 obj_val = 00416 ((query_numeric_getter) getter->param_getfcn) (object, getter); 00417 00418 switch (pdata->options) 00419 { 00420 case QOF_NUMERIC_MATCH_CREDIT: 00421 if (qof_numeric_positive_p (obj_val)) 00422 return 0; 00423 break; 00424 case QOF_NUMERIC_MATCH_DEBIT: 00425 if (qof_numeric_negative_p (obj_val)) 00426 return 0; 00427 break; 00428 default: 00429 break; 00430 } 00431 00432 /* Amounts are considered to be 'equal' if they match to 00433 * four decimal places. (epsilon=1/10000) */ 00434 if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ) 00435 { 00436 QofNumeric cmp_val = qof_numeric_create (1, 10000); 00437 compare = 00438 (qof_numeric_compare (qof_numeric_abs 00439 (qof_numeric_sub (qof_numeric_abs (obj_val), 00440 qof_numeric_abs (pdata-> 00441 amount), 00442 100000, QOF_HOW_RND_ROUND)), cmp_val) < 0); 00443 } 00444 else 00445 compare = 00446 qof_numeric_compare (qof_numeric_abs (obj_val), pdata->amount); 00447 00448 switch (pd->how) 00449 { 00450 case QOF_COMPARE_LT: 00451 return (compare < 0); 00452 case QOF_COMPARE_LTE: 00453 return (compare <= 0); 00454 case QOF_COMPARE_EQUAL: 00455 return compare; 00456 case QOF_COMPARE_GT: 00457 return (compare > 0); 00458 case QOF_COMPARE_GTE: 00459 return (compare >= 0); 00460 case QOF_COMPARE_NEQ: 00461 return !compare; 00462 default: 00463 PWARN ("bad match type: %d", pd->how); 00464 return 0; 00465 } 00466 } 00467 00468 static int 00469 numeric_compare_func (gpointer a, gpointer b, 00470 gint options __attribute__ ((unused)), QofParam * getter) 00471 { 00472 QofNumeric va, vb; 00473 00474 g_return_val_if_fail (a && b && getter 00475 && getter->param_getfcn, COMPARE_ERROR); 00476 00477 va = ((query_numeric_getter) getter->param_getfcn) (a, getter); 00478 vb = ((query_numeric_getter) getter->param_getfcn) (b, getter); 00479 00480 return qof_numeric_compare (va, vb); 00481 } 00482 00483 static void 00484 numeric_free_pdata (QofQueryPredData * pd) 00485 { 00486 query_numeric_t pdata = (query_numeric_t) pd; 00487 VERIFY_PDATA (query_numeric_type); 00488 g_free (pdata); 00489 } 00490 00491 static QofQueryPredData * 00492 numeric_copy_predicate (QofQueryPredData * pd) 00493 { 00494 query_numeric_t pdata = (query_numeric_t) pd; 00495 VERIFY_PDATA_R (query_numeric_type); 00496 return qof_query_numeric_predicate (pd->how, pdata->options, 00497 pdata->amount); 00498 } 00499 00500 static gboolean 00501 numeric_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00502 { 00503 query_numeric_t pd1 = (query_numeric_t) p1; 00504 query_numeric_t pd2 = (query_numeric_t) p2; 00505 00506 if (pd1->options != pd2->options) 00507 return FALSE; 00508 return qof_numeric_equal (pd1->amount, pd2->amount); 00509 } 00510 00511 QofQueryPredData * 00512 qof_query_numeric_predicate (QofQueryCompare how, 00513 QofNumericMatch options, QofNumeric value) 00514 { 00515 query_numeric_t pdata; 00516 pdata = g_new0 (query_numeric_def, 1); 00517 pdata->pd.type_name = query_numeric_type; 00518 pdata->pd.how = how; 00519 pdata->options = options; 00520 pdata->amount = value; 00521 return ((QofQueryPredData *) pdata); 00522 } 00523 00524 static char * 00525 numeric_to_string (gpointer object, QofParam * getter) 00526 { 00527 QofNumeric num; 00528 num = ((query_numeric_getter) getter->param_getfcn) (object, getter); 00529 00530 return qof_numeric_to_string (num); 00531 } 00532 00533 static char * 00534 debcred_to_string (gpointer object, QofParam * getter) 00535 { 00536 QofNumeric num; 00537 num = ((query_numeric_getter) getter->param_getfcn) (object, getter); 00538 00539 return qof_numeric_to_string (num); 00540 } 00541 00542 /* QOF_TYPE_GUID =================================================== */ 00543 00544 static int 00545 guid_match_predicate (gpointer object, QofParam * getter, 00546 QofQueryPredData * pd) 00547 { 00548 query_guid_t pdata = (query_guid_t) pd; 00549 GList *node, *o_list; 00550 const GUID *guid = NULL; 00551 00552 VERIFY_PREDICATE (query_guid_type); 00553 00554 switch (pdata->options) 00555 { 00556 00557 case QOF_GUID_MATCH_ALL: 00558 /* object is a GList of objects; param_getfcn must be called on each one. 00559 * See if every guid in the predicate is accounted-for in the 00560 * object list 00561 */ 00562 00563 for (node = pdata->guids; node; node = node->next) 00564 { 00565 /* See if this GUID matches the object's guid */ 00566 for (o_list = object; o_list; o_list = o_list->next) 00567 { 00568 guid = 00569 ((query_guid_getter) getter->param_getfcn) (o_list-> 00570 data, getter); 00571 if (guid_equal (node->data, guid)) 00572 break; 00573 } 00574 00575 /* 00576 * If o_list is NULL, we've walked the whole list without finding 00577 * a match. Therefore break out now, the match has failed. 00578 */ 00579 if (o_list == NULL) 00580 break; 00581 } 00582 00583 /* 00584 * The match is complete. If node == NULL then we've succesfully 00585 * found a match for all the guids in the predicate. Return 00586 * appropriately below. 00587 */ 00588 00589 break; 00590 00591 case QOF_GUID_MATCH_LIST_ANY: 00592 /* object is a single object, getter returns a GList* of GUID* 00593 * 00594 * See if any GUID* in the returned list matches any guid in the 00595 * predicate match list. 00596 */ 00597 00598 o_list = 00599 ((query_glist_getter) getter->param_getfcn) (object, getter); 00600 00601 for (node = o_list; node; node = node->next) 00602 { 00603 GList *node2; 00604 00605 /* Search the predicate data for a match */ 00606 for (node2 = pdata->guids; node2; node2 = node2->next) 00607 { 00608 if (guid_equal (node->data, node2->data)) 00609 break; 00610 } 00611 00612 /* Check to see if we found a match. If so, break now */ 00613 if (node2 != NULL) 00614 break; 00615 } 00616 00617 g_list_free (o_list); 00618 00619 /* yea, node may point to an invalid location, but that's ok. 00620 * we're not _USING_ the value, just checking that it's non-NULL 00621 */ 00622 00623 break; 00624 00625 default: 00626 /* object is a single object, getter returns a GUID* 00627 * 00628 * See if the guid is in the list 00629 */ 00630 00631 guid = ((query_guid_getter) getter->param_getfcn) (object, getter); 00632 for (node = pdata->guids; node; node = node->next) 00633 { 00634 if (guid_equal (node->data, guid)) 00635 break; 00636 } 00637 } 00638 00639 switch (pdata->options) 00640 { 00641 case QOF_GUID_MATCH_ANY: 00642 case QOF_GUID_MATCH_LIST_ANY: 00643 return (node != NULL); 00644 break; 00645 case QOF_GUID_MATCH_NONE: 00646 case QOF_GUID_MATCH_ALL: 00647 return (node == NULL); 00648 break; 00649 case QOF_GUID_MATCH_NULL: 00650 return (guid == NULL); 00651 break; 00652 default: 00653 PWARN ("bad match type"); 00654 return 0; 00655 } 00656 } 00657 00658 static void 00659 guid_free_pdata (QofQueryPredData * pd) 00660 { 00661 query_guid_t pdata = (query_guid_t) pd; 00662 GList *node; 00663 VERIFY_PDATA (query_guid_type); 00664 for (node = pdata->guids; node; node = node->next) 00665 { 00666 guid_free (node->data); 00667 } 00668 g_list_free (pdata->guids); 00669 g_free (pdata); 00670 } 00671 00672 static QofQueryPredData * 00673 guid_copy_predicate (QofQueryPredData * pd) 00674 { 00675 query_guid_t pdata = (query_guid_t) pd; 00676 VERIFY_PDATA_R (query_guid_type); 00677 return qof_query_guid_predicate (pdata->options, pdata->guids); 00678 } 00679 00680 static gboolean 00681 guid_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00682 { 00683 query_guid_t pd1 = (query_guid_t) p1; 00684 query_guid_t pd2 = (query_guid_t) p2; 00685 GList *l1 = pd1->guids, *l2 = pd2->guids; 00686 00687 if (pd1->options != pd2->options) 00688 return FALSE; 00689 if (g_list_length (l1) != g_list_length (l2)) 00690 return FALSE; 00691 for (; l1; l1 = l1->next, l2 = l2->next) 00692 { 00693 if (!guid_equal (l1->data, l2->data)) 00694 return FALSE; 00695 } 00696 return TRUE; 00697 } 00698 00699 QofQueryPredData * 00700 qof_query_guid_predicate (QofGuidMatch options, GList * guid_list) 00701 { 00702 query_guid_t pdata; 00703 GList *node; 00704 00705 if (NULL == guid_list) 00706 return NULL; 00707 00708 pdata = g_new0 (query_guid_def, 1); 00709 pdata->pd.how = QOF_COMPARE_EQUAL; 00710 pdata->pd.type_name = query_guid_type; 00711 pdata->options = options; 00712 00713 pdata->guids = g_list_copy (guid_list); 00714 for (node = pdata->guids; node; node = node->next) 00715 { 00716 GUID *guid = guid_malloc (); 00717 *guid = *((GUID *) node->data); 00718 node->data = guid; 00719 } 00720 return ((QofQueryPredData *) pdata); 00721 } 00722 00723 /* ================================================================ */ 00724 /* QOF_TYPE_INT32 */ 00725 00726 static int 00727 int32_match_predicate (gpointer object, QofParam * getter, 00728 QofQueryPredData * pd) 00729 { 00730 gint32 val; 00731 query_int32_t pdata = (query_int32_t) pd; 00732 00733 VERIFY_PREDICATE (query_int32_type); 00734 00735 val = ((query_int32_getter) getter->param_getfcn) (object, getter); 00736 00737 switch (pd->how) 00738 { 00739 case QOF_COMPARE_LT: 00740 return (val < pdata->val); 00741 case QOF_COMPARE_LTE: 00742 return (val <= pdata->val); 00743 case QOF_COMPARE_EQUAL: 00744 return (val == pdata->val); 00745 case QOF_COMPARE_GT: 00746 return (val > pdata->val); 00747 case QOF_COMPARE_GTE: 00748 return (val >= pdata->val); 00749 case QOF_COMPARE_NEQ: 00750 return (val != pdata->val); 00751 default: 00752 PWARN ("bad match type: %d", pd->how); 00753 return 0; 00754 } 00755 } 00756 00757 static int 00758 int32_compare_func (gpointer a, gpointer b, 00759 gint options __attribute__ ((unused)), 00760 QofParam * getter) 00761 { 00762 gint32 v1, v2; 00763 g_return_val_if_fail (a && b && getter 00764 && getter->param_getfcn, COMPARE_ERROR); 00765 00766 v1 = ((query_int32_getter) getter->param_getfcn) (a, getter); 00767 v2 = ((query_int32_getter) getter->param_getfcn) (b, getter); 00768 00769 if (v1 < v2) 00770 return -1; 00771 if (v1 > v2) 00772 return 1; 00773 return 0; 00774 } 00775 00776 static void 00777 int32_free_pdata (QofQueryPredData * pd) 00778 { 00779 query_int32_t pdata = (query_int32_t) pd; 00780 VERIFY_PDATA (query_int32_type); 00781 g_free (pdata); 00782 } 00783 00784 static QofQueryPredData * 00785 int32_copy_predicate (QofQueryPredData * pd) 00786 { 00787 query_int32_t pdata = (query_int32_t) pd; 00788 VERIFY_PDATA_R (query_int32_type); 00789 return qof_query_int32_predicate (pd->how, pdata->val); 00790 } 00791 00792 static gboolean 00793 int32_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00794 { 00795 query_int32_t pd1 = (query_int32_t) p1; 00796 query_int32_t pd2 = (query_int32_t) p2; 00797 00798 return (pd1->val == pd2->val); 00799 } 00800 00801 QofQueryPredData * 00802 qof_query_int32_predicate (QofQueryCompare how, gint32 val) 00803 { 00804 query_int32_t pdata = g_new0 (query_int32_def, 1); 00805 pdata->pd.type_name = query_int32_type; 00806 pdata->pd.how = how; 00807 pdata->val = val; 00808 return ((QofQueryPredData *) pdata); 00809 } 00810 00811 static char * 00812 int32_to_string (gpointer object, QofParam * getter) 00813 { 00814 gint32 num = 00815 ((query_int32_getter) getter->param_getfcn) (object, getter); 00816 00817 return g_strdup_printf ("%d", num); 00818 } 00819 00820 /* ================================================================ */ 00821 /* QOF_TYPE_INT64 */ 00822 00823 static int 00824 int64_match_predicate (gpointer object, QofParam * getter, 00825 QofQueryPredData * pd) 00826 { 00827 gint64 val; 00828 query_int64_t pdata = (query_int64_t) pd; 00829 00830 VERIFY_PREDICATE (query_int64_type); 00831 00832 val = ((query_int64_getter) getter->param_getfcn) (object, getter); 00833 00834 switch (pd->how) 00835 { 00836 case QOF_COMPARE_LT: 00837 return (val < pdata->val); 00838 case QOF_COMPARE_LTE: 00839 return (val <= pdata->val); 00840 case QOF_COMPARE_EQUAL: 00841 return (val == pdata->val); 00842 case QOF_COMPARE_GT: 00843 return (val > pdata->val); 00844 case QOF_COMPARE_GTE: 00845 return (val >= pdata->val); 00846 case QOF_COMPARE_NEQ: 00847 return (val != pdata->val); 00848 default: 00849 PWARN ("bad match type: %d", pd->how); 00850 return 0; 00851 } 00852 } 00853 00854 static int 00855 int64_compare_func (gpointer a, gpointer b, 00856 gint options __attribute__ ((unused)), QofParam * getter) 00857 { 00858 gint64 v1, v2; 00859 g_return_val_if_fail (a && b && getter 00860 && getter->param_getfcn, COMPARE_ERROR); 00861 00862 v1 = ((query_int64_getter) getter->param_getfcn) (a, getter); 00863 v2 = ((query_int64_getter) getter->param_getfcn) (b, getter); 00864 00865 if (v1 < v2) 00866 return -1; 00867 if (v1 > v2) 00868 return 1; 00869 return 0; 00870 } 00871 00872 static void 00873 int64_free_pdata (QofQueryPredData * pd) 00874 { 00875 query_int64_t pdata = (query_int64_t) pd; 00876 VERIFY_PDATA (query_int64_type); 00877 g_free (pdata); 00878 } 00879 00880 static QofQueryPredData * 00881 int64_copy_predicate (QofQueryPredData * pd) 00882 { 00883 query_int64_t pdata = (query_int64_t) pd; 00884 VERIFY_PDATA_R (query_int64_type); 00885 return qof_query_int64_predicate (pd->how, pdata->val); 00886 } 00887 00888 static gboolean 00889 int64_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00890 { 00891 query_int64_t pd1 = (query_int64_t) p1; 00892 query_int64_t pd2 = (query_int64_t) p2; 00893 00894 return (pd1->val == pd2->val); 00895 } 00896 00897 QofQueryPredData * 00898 qof_query_int64_predicate (QofQueryCompare how, gint64 val) 00899 { 00900 query_int64_t pdata = g_new0 (query_int64_def, 1); 00901 pdata->pd.type_name = query_int64_type; 00902 pdata->pd.how = how; 00903 pdata->val = val; 00904 return ((QofQueryPredData *) pdata); 00905 } 00906 00907 static char * 00908 int64_to_string (gpointer object, QofParam * getter) 00909 { 00910 gint64 num = 00911 ((query_int64_getter) getter->param_getfcn) (object, getter); 00912 00913 return g_strdup_printf ("%" G_GINT64_FORMAT, num); 00914 } 00915 00916 /* ================================================================ */ 00917 /* QOF_TYPE_DOUBLE */ 00918 00919 static int 00920 double_match_predicate (gpointer object, QofParam * getter, 00921 QofQueryPredData * pd) 00922 { 00923 double val; 00924 query_double_t pdata = (query_double_t) pd; 00925 00926 VERIFY_PREDICATE (query_double_type); 00927 00928 val = ((query_double_getter) getter->param_getfcn) (object, getter); 00929 00930 switch (pd->how) 00931 { 00932 case QOF_COMPARE_LT: 00933 return (val < pdata->val); 00934 case QOF_COMPARE_LTE: 00935 return (val <= pdata->val); 00936 case QOF_COMPARE_EQUAL: 00937 return (val == pdata->val); 00938 case QOF_COMPARE_GT: 00939 return (val > pdata->val); 00940 case QOF_COMPARE_GTE: 00941 return (val >= pdata->val); 00942 case QOF_COMPARE_NEQ: 00943 return (val != pdata->val); 00944 default: 00945 PWARN ("bad match type: %d", pd->how); 00946 return 0; 00947 } 00948 } 00949 00950 static int 00951 double_compare_func (gpointer a, gpointer b, 00952 gint options __attribute__ ((unused)), QofParam * getter) 00953 { 00954 double v1, v2; 00955 g_return_val_if_fail (a && b && getter 00956 && getter->param_getfcn, COMPARE_ERROR); 00957 00958 v1 = ((query_double_getter) getter->param_getfcn) (a, getter); 00959 v2 = ((query_double_getter) getter->param_getfcn) (b, getter); 00960 00961 if (v1 < v2) 00962 return -1; 00963 if (v1 > v2) 00964 return 1; 00965 return 0; 00966 } 00967 00968 static void 00969 double_free_pdata (QofQueryPredData * pd) 00970 { 00971 query_double_t pdata = (query_double_t) pd; 00972 VERIFY_PDATA (query_double_type); 00973 g_free (pdata); 00974 } 00975 00976 static QofQueryPredData * 00977 double_copy_predicate (QofQueryPredData * pd) 00978 { 00979 query_double_t pdata = (query_double_t) pd; 00980 VERIFY_PDATA_R (query_double_type); 00981 return qof_query_double_predicate (pd->how, pdata->val); 00982 } 00983 00984 static gboolean 00985 double_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 00986 { 00987 query_double_t pd1 = (query_double_t) p1; 00988 query_double_t pd2 = (query_double_t) p2; 00989 00990 return (pd1->val == pd2->val); 00991 } 00992 00993 QofQueryPredData * 00994 qof_query_double_predicate (QofQueryCompare how, double val) 00995 { 00996 query_double_t pdata = g_new0 (query_double_def, 1); 00997 pdata->pd.type_name = query_double_type; 00998 pdata->pd.how = how; 00999 pdata->val = val; 01000 return ((QofQueryPredData *) pdata); 01001 } 01002 01003 static char * 01004 double_to_string (gpointer object, QofParam * getter) 01005 { 01006 double num = 01007 ((query_double_getter) getter->param_getfcn) (object, getter); 01008 01009 return g_strdup_printf ("%f", num); 01010 } 01011 01012 /* QOF_TYPE_BOOLEAN =================================================== */ 01013 01014 static int 01015 boolean_match_predicate (gpointer object, QofParam * getter, 01016 QofQueryPredData * pd) 01017 { 01018 gboolean val; 01019 query_boolean_t pdata = (query_boolean_t) pd; 01020 01021 VERIFY_PREDICATE (query_boolean_type); 01022 01023 val = ((query_boolean_getter) getter->param_getfcn) (object, getter); 01024 01025 switch (pd->how) 01026 { 01027 case QOF_COMPARE_EQUAL: 01028 return (val == pdata->val); 01029 case QOF_COMPARE_NEQ: 01030 return (val != pdata->val); 01031 default: 01032 PWARN ("bad match type: %d", pd->how); 01033 return 0; 01034 } 01035 } 01036 01037 static int 01038 boolean_compare_func (gpointer a, gpointer b, 01039 gint options __attribute__ ((unused)), QofParam * getter) 01040 { 01041 gboolean va, vb; 01042 g_return_val_if_fail (a && b && getter 01043 && getter->param_getfcn, COMPARE_ERROR); 01044 va = ((query_boolean_getter) getter->param_getfcn) (a, getter); 01045 vb = ((query_boolean_getter) getter->param_getfcn) (b, getter); 01046 if (!va && vb) 01047 return -1; 01048 if (va && !vb) 01049 return 1; 01050 return 0; 01051 } 01052 01053 static void 01054 boolean_free_pdata (QofQueryPredData * pd) 01055 { 01056 query_boolean_t pdata = (query_boolean_t) pd; 01057 VERIFY_PDATA (query_boolean_type); 01058 g_free (pdata); 01059 } 01060 01061 static QofQueryPredData * 01062 boolean_copy_predicate (QofQueryPredData * pd) 01063 { 01064 query_boolean_t pdata = (query_boolean_t) pd; 01065 VERIFY_PDATA_R (query_boolean_type); 01066 return qof_query_boolean_predicate (pd->how, pdata->val); 01067 } 01068 01069 static gboolean 01070 boolean_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 01071 { 01072 query_boolean_t pd1 = (query_boolean_t) p1; 01073 query_boolean_t pd2 = (query_boolean_t) p2; 01074 01075 return (pd1->val == pd2->val); 01076 } 01077 01078 QofQueryPredData * 01079 qof_query_boolean_predicate (QofQueryCompare how, gboolean val) 01080 { 01081 query_boolean_t pdata; 01082 g_return_val_if_fail (how == QOF_COMPARE_EQUAL 01083 || how == QOF_COMPARE_NEQ, NULL); 01084 01085 pdata = g_new0 (query_boolean_def, 1); 01086 pdata->pd.type_name = query_boolean_type; 01087 pdata->pd.how = how; 01088 pdata->val = val; 01089 return ((QofQueryPredData *) pdata); 01090 } 01091 01092 static char * 01093 boolean_to_string (gpointer object, QofParam * getter) 01094 { 01095 gboolean num = 01096 ((query_boolean_getter) getter->param_getfcn) (object, getter); 01097 01098 return g_strdup_printf ("%s", (num ? "X" : "")); 01099 } 01100 01101 /* QOF_TYPE_CHAR =================================================== */ 01102 01103 static int 01104 char_match_predicate (gpointer object, QofParam * getter, 01105 QofQueryPredData * pd) 01106 { 01107 char c; 01108 query_char_t pdata = (query_char_t) pd; 01109 01110 VERIFY_PREDICATE (query_char_type); 01111 01112 c = ((query_char_getter) getter->param_getfcn) (object, getter); 01113 01114 switch (pdata->options) 01115 { 01116 case QOF_CHAR_MATCH_ANY: 01117 if (strchr (pdata->char_list, c)) 01118 return 1; 01119 return 0; 01120 case QOF_CHAR_MATCH_NONE: 01121 if (!strchr (pdata->char_list, c)) 01122 return 1; 01123 return 0; 01124 default: 01125 PWARN ("bad match type"); 01126 return 0; 01127 } 01128 } 01129 01130 static int 01131 char_compare_func (gpointer a, gpointer b, 01132 gint options __attribute__ ((unused)), QofParam * getter) 01133 { 01134 char va, vb; 01135 g_return_val_if_fail (a && b && getter 01136 && getter->param_getfcn, COMPARE_ERROR); 01137 va = ((query_char_getter) getter->param_getfcn) (a, getter); 01138 vb = ((query_char_getter) getter->param_getfcn) (b, getter); 01139 return (va - vb); 01140 } 01141 01142 static void 01143 char_free_pdata (QofQueryPredData * pd) 01144 { 01145 query_char_t pdata = (query_char_t) pd; 01146 VERIFY_PDATA (query_char_type); 01147 g_free (pdata->char_list); 01148 g_free (pdata); 01149 } 01150 01151 static QofQueryPredData * 01152 char_copy_predicate (QofQueryPredData * pd) 01153 { 01154 query_char_t pdata = (query_char_t) pd; 01155 VERIFY_PDATA_R (query_char_type); 01156 return qof_query_char_predicate (pdata->options, pdata->char_list); 01157 } 01158 01159 static gboolean 01160 char_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 01161 { 01162 query_char_t pd1 = (query_char_t) p1; 01163 query_char_t pd2 = (query_char_t) p2; 01164 01165 if (pd1->options != pd2->options) 01166 return FALSE; 01167 return (safe_strcmp (pd1->char_list, pd2->char_list) == 0); 01168 } 01169 01170 QofQueryPredData * 01171 qof_query_char_predicate (QofCharMatch options, const char *chars) 01172 { 01173 query_char_t pdata; 01174 g_return_val_if_fail (chars, NULL); 01175 pdata = g_new0 (query_char_def, 1); 01176 pdata->pd.type_name = query_char_type; 01177 pdata->pd.how = QOF_COMPARE_EQUAL; 01178 pdata->options = options; 01179 pdata->char_list = g_strdup (chars); 01180 return ((QofQueryPredData *) pdata); 01181 } 01182 01183 static char * 01184 char_to_string (gpointer object, QofParam * getter) 01185 { 01186 char num = ((query_char_getter) getter->param_getfcn) (object, getter); 01187 01188 return g_strdup_printf ("%c", num); 01189 } 01190 01191 /* QOF_TYPE_KVP ================================================ */ 01192 01193 static int 01194 kvp_match_predicate (gpointer object, QofParam * getter, 01195 QofQueryPredData * pd) 01196 { 01197 int compare; 01198 KvpFrame *kvp; 01199 KvpValue *value; 01200 query_kvp_t pdata = (query_kvp_t) pd; 01201 01202 VERIFY_PREDICATE (query_kvp_type); 01203 01204 kvp = ((query_kvp_getter) getter->param_getfcn) (object, getter); 01205 if (!kvp) 01206 return 0; 01207 01208 value = kvp_frame_get_slot_path_gslist (kvp, pdata->path); 01209 if (!value) 01210 return 0; 01211 01212 if (kvp_value_get_type (value) != kvp_value_get_type (pdata->value)) 01213 return 0; 01214 01215 compare = kvp_value_compare (value, pdata->value); 01216 01217 switch (pd->how) 01218 { 01219 case QOF_COMPARE_LT: 01220 return (compare < 0); 01221 case QOF_COMPARE_LTE: 01222 return (compare <= 0); 01223 case QOF_COMPARE_EQUAL: 01224 return (compare == 0); 01225 case QOF_COMPARE_GTE: 01226 return (compare >= 0); 01227 case QOF_COMPARE_GT: 01228 return (compare > 0); 01229 case QOF_COMPARE_NEQ: 01230 return (compare != 0); 01231 default: 01232 PWARN ("bad match type: %d", pd->how); 01233 return 0; 01234 } 01235 } 01236 01237 static void 01238 kvp_free_pdata (QofQueryPredData * pd) 01239 { 01240 query_kvp_t pdata = (query_kvp_t) pd; 01241 GSList *node; 01242 01243 VERIFY_PDATA (query_kvp_type); 01244 kvp_value_delete (pdata->value); 01245 for (node = pdata->path; node; node = node->next) 01246 { 01247 g_free (node->data); 01248 node->data = NULL; 01249 } 01250 g_slist_free (pdata->path); 01251 g_free (pdata); 01252 } 01253 01254 static QofQueryPredData * 01255 kvp_copy_predicate (QofQueryPredData * pd) 01256 { 01257 query_kvp_t pdata = (query_kvp_t) pd; 01258 VERIFY_PDATA_R (query_kvp_type); 01259 return qof_query_kvp_predicate (pd->how, pdata->path, pdata->value); 01260 } 01261 01262 static gboolean 01263 kvp_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 01264 { 01265 query_kvp_t pd1 = (query_kvp_t) p1; 01266 query_kvp_t pd2 = (query_kvp_t) p2; 01267 GSList *n1, *n2; 01268 01269 n1 = pd1->path; 01270 n2 = pd2->path; 01271 01272 for (; n1 && n2; n1 = n1->next, n2 = n2->next) 01273 { 01274 if (safe_strcmp (n1->data, n2->data) != 0) 01275 return FALSE; 01276 } 01277 01278 if (n1 || n2) 01279 return FALSE; 01280 01281 return (kvp_value_compare (pd1->value, pd2->value) == 0); 01282 } 01283 01284 QofQueryPredData * 01285 qof_query_kvp_predicate (QofQueryCompare how, 01286 GSList * path, const KvpValue * value) 01287 { 01288 query_kvp_t pdata; 01289 GSList *node; 01290 01291 g_return_val_if_fail (path && value, NULL); 01292 01293 pdata = g_new0 (query_kvp_def, 1); 01294 pdata->pd.type_name = query_kvp_type; 01295 pdata->pd.how = how; 01296 pdata->value = kvp_value_copy (value); 01297 pdata->path = g_slist_copy (path); 01298 for (node = pdata->path; node; node = node->next) 01299 node->data = g_strdup (node->data); 01300 01301 return ((QofQueryPredData *) pdata); 01302 } 01303 01304 QofQueryPredData * 01305 qof_query_kvp_predicate_path (QofQueryCompare how, 01306 const char *path, const KvpValue * value) 01307 { 01308 QofQueryPredData *pd; 01309 GSList *spath = NULL; 01310 char *str, *p; 01311 01312 if (!path) 01313 return NULL; 01314 01315 str = g_strdup (path); 01316 p = str; 01317 if (0 == *p) 01318 return NULL; 01319 if ('/' == *p) 01320 p++; 01321 01322 while (p) 01323 { 01324 spath = g_slist_append (spath, p); 01325 p = strchr (p, '/'); 01326 if (p) 01327 { 01328 *p = 0; 01329 p++; 01330 } 01331 } 01332 01333 pd = qof_query_kvp_predicate (how, spath, value); 01334 g_free (str); 01335 return pd; 01336 } 01337 01338 01339 /* QOF_TYPE_COLLECT =============================================== */ 01340 01341 static int 01342 collect_match_predicate (gpointer object, QofParam * getter, 01343 QofQueryPredData * pd) 01344 { 01345 query_coll_t pdata; 01346 QofCollection * G_GNUC_UNUSED coll; 01347 GList *node, *node2, *o_list; 01348 const GUID *guid; 01349 01350 pdata = (query_coll_t) pd; 01351 VERIFY_PREDICATE (query_collect_type); 01352 coll = ((query_collect_getter) getter->param_getfcn) (object, getter); 01353 guid = NULL; 01354 switch (pdata->options) 01355 { 01356 case QOF_GUID_MATCH_ALL: 01357 { 01358 for (node = pdata->guids; node; node = node->next) 01359 { 01360 for (o_list = object; o_list; o_list = o_list->next) 01361 { 01362 guid = ((query_guid_getter) getter->param_getfcn) 01363 (o_list->data, getter); 01364 if (guid_equal (node->data, guid)) 01365 { 01366 break; 01367 } 01368 } 01369 if (o_list == NULL) 01370 { 01371 break; 01372 } 01373 } 01374 break; 01375 } 01376 case QOF_GUID_MATCH_LIST_ANY: 01377 { 01378 o_list = 01379 ((query_glist_getter) getter->param_getfcn) (object, 01380 getter); 01381 for (node = o_list; node; node = node->next) 01382 { 01383 for (node2 = pdata->guids; node2; node2 = node2->next) 01384 { 01385 if (guid_equal (node->data, node2->data)) 01386 { 01387 break; 01388 } 01389 } 01390 if (node2 != NULL) 01391 { 01392 break; 01393 } 01394 } 01395 g_list_free (o_list); 01396 break; 01397 } 01398 default: 01399 { 01400 guid = 01401 ((query_guid_getter) getter->param_getfcn) (object, 01402 getter); 01403 for (node = pdata->guids; node; node = node->next) 01404 { 01405 if (guid_equal (node->data, guid)) 01406 { 01407 break; 01408 } 01409 } 01410 } 01411 switch (pdata->options) 01412 { 01413 case QOF_GUID_MATCH_ANY: 01414 case QOF_GUID_MATCH_LIST_ANY: 01415 { 01416 return (node != NULL); 01417 break; 01418 } 01419 case QOF_GUID_MATCH_NONE: 01420 case QOF_GUID_MATCH_ALL: 01421 { 01422 return (node == NULL); 01423 break; 01424 } 01425 case QOF_GUID_MATCH_NULL: 01426 { 01427 return (guid == NULL); 01428 break; 01429 } 01430 default: 01431 { 01432 PWARN ("bad match type"); 01433 return 0; 01434 } 01435 } 01436 } 01437 return 0; 01438 } 01439 01440 static int 01441 collect_compare_func (gpointer a, gpointer b, 01442 gint options __attribute__ ((unused)), 01443 QofParam * getter) 01444 { 01445 gint result; 01446 QofCollection *c1, *c2; 01447 01448 c1 = ((query_collect_getter) getter->param_getfcn) (a, getter); 01449 c2 = ((query_collect_getter) getter->param_getfcn) (b, getter); 01450 result = qof_collection_compare (c1, c2); 01451 return result; 01452 } 01453 01454 static void 01455 collect_free_pdata (QofQueryPredData * pd) 01456 { 01457 query_coll_t pdata; 01458 GList *node; 01459 01460 node = NULL; 01461 pdata = (query_coll_t) pd; 01462 VERIFY_PDATA (query_collect_type); 01463 for (node = pdata->guids; node; node = node->next) 01464 { 01465 guid_free (node->data); 01466 } 01467 qof_collection_destroy (pdata->coll); 01468 g_list_free (pdata->guids); 01469 g_free (pdata); 01470 } 01471 01472 static QofQueryPredData * 01473 collect_copy_predicate (QofQueryPredData * pd) 01474 { 01475 query_coll_t pdata = (query_coll_t) pd; 01476 01477 VERIFY_PDATA_R (query_collect_type); 01478 return qof_query_collect_predicate (pdata->options, pdata->coll); 01479 } 01480 01481 static gboolean 01482 collect_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 01483 { 01484 query_coll_t pd1; 01485 query_coll_t pd2; 01486 gint result; 01487 01488 pd1 = (query_coll_t) p1; 01489 pd2 = (query_coll_t) p2; 01490 result = qof_collection_compare (pd1->coll, pd2->coll); 01491 if (result == 0) 01492 { 01493 return TRUE; 01494 } 01495 return FALSE; 01496 } 01497 01498 static void 01499 query_collect_cb (QofEntity * ent, gpointer user_data) 01500 { 01501 query_coll_t pdata; 01502 GUID *guid; 01503 01504 guid = guid_malloc (); 01505 guid = (GUID *) qof_entity_get_guid (ent); 01506 pdata = (query_coll_t) user_data; 01507 pdata->guids = g_list_append (pdata->guids, guid); 01508 } 01509 01510 QofQueryPredData * 01511 qof_query_collect_predicate (QofGuidMatch options, QofCollection * coll) 01512 { 01513 query_coll_t pdata; 01514 01515 g_return_val_if_fail (coll, NULL); 01516 pdata = g_new0 (query_coll_def, 1); 01517 pdata->pd.type_name = query_collect_type; 01518 pdata->options = options; 01519 qof_collection_foreach (coll, query_collect_cb, pdata); 01520 if (NULL == pdata->guids) 01521 { 01522 return NULL; 01523 } 01524 return ((QofQueryPredData *) pdata); 01525 } 01526 01527 /* QOF_TYPE_CHOICE */ 01528 01529 static int 01530 choice_match_predicate (gpointer object, QofParam * getter, 01531 QofQueryPredData * pd) 01532 { 01533 query_choice_t pdata = (query_choice_t) pd; 01534 GList *node, *o_list; 01535 const GUID *guid = NULL; 01536 01537 VERIFY_PREDICATE (query_choice_type); 01538 01539 switch (pdata->options) 01540 { 01541 01542 case QOF_GUID_MATCH_ALL: 01543 /* object is a GList of objects; param_getfcn must be called on each one. 01544 * See if every guid in the predicate is accounted-for in the 01545 * object list 01546 */ 01547 01548 for (node = pdata->guids; node; node = node->next) 01549 { 01550 /* See if this GUID matches the object's guid */ 01551 for (o_list = object; o_list; o_list = o_list->next) 01552 { 01553 guid = 01554 ((query_choice_getter) getter->param_getfcn) (o_list-> 01555 data, getter); 01556 if (guid_equal (node->data, guid)) 01557 break; 01558 } 01559 01560 /* 01561 * If o_list is NULL, we've walked the whole list without finding 01562 * a match. Therefore break out now, the match has failed. 01563 */ 01564 if (o_list == NULL) 01565 break; 01566 } 01567 01568 /* 01569 * The match is complete. If node == NULL then we've succesfully 01570 * found a match for all the guids in the predicate. Return 01571 * appropriately below. 01572 */ 01573 01574 break; 01575 01576 case QOF_GUID_MATCH_LIST_ANY: 01577 01578 o_list = 01579 ((query_glist_getter) getter->param_getfcn) (object, getter); 01580 01581 for (node = o_list; node; node = node->next) 01582 { 01583 GList *node2; 01584 01585 for (node2 = pdata->guids; node2; node2 = node2->next) 01586 { 01587 if (guid_equal (node->data, node2->data)) 01588 break; 01589 } 01590 01591 if (node2 != NULL) 01592 break; 01593 } 01594 01595 g_list_free (o_list); 01596 01597 break; 01598 01599 default: 01600 /* object is a single object, getter returns a GUID* 01601 * 01602 * See if the guid is in the list 01603 */ 01604 01605 guid = 01606 ((query_choice_getter) getter->param_getfcn) (object, getter); 01607 for (node = pdata->guids; node; node = node->next) 01608 { 01609 if (guid_equal (node->data, guid)) 01610 break; 01611 } 01612 } 01613 01614 switch (pdata->options) 01615 { 01616 case QOF_GUID_MATCH_ANY: 01617 case QOF_GUID_MATCH_LIST_ANY: 01618 return (node != NULL); 01619 break; 01620 case QOF_GUID_MATCH_NONE: 01621 case QOF_GUID_MATCH_ALL: 01622 return (node == NULL); 01623 break; 01624 case QOF_GUID_MATCH_NULL: 01625 return (guid == NULL); 01626 break; 01627 default: 01628 PWARN ("bad match type"); 01629 return 0; 01630 } 01631 } 01632 01633 static void 01634 choice_free_pdata (QofQueryPredData * pd) 01635 { 01636 query_choice_t pdata = (query_choice_t) pd; 01637 GList *node; 01638 VERIFY_PDATA (query_choice_type); 01639 for (node = pdata->guids; node; node = node->next) 01640 { 01641 guid_free (node->data); 01642 } 01643 g_list_free (pdata->guids); 01644 g_free (pdata); 01645 } 01646 01647 static QofQueryPredData * 01648 choice_copy_predicate (QofQueryPredData * pd) 01649 { 01650 query_choice_t pdata = (query_choice_t) pd; 01651 VERIFY_PDATA_R (query_choice_type); 01652 return qof_query_choice_predicate (pdata->options, pdata->guids); 01653 } 01654 01655 static gboolean 01656 choice_predicate_equal (QofQueryPredData * p1, QofQueryPredData * p2) 01657 { 01658 query_choice_t pd1 = (query_choice_t) p1; 01659 query_choice_t pd2 = (query_choice_t) p2; 01660 GList *l1 = pd1->guids, *l2 = pd2->guids; 01661 01662 if (pd1->options != pd2->options) 01663 return FALSE; 01664 if (g_list_length (l1) != g_list_length (l2)) 01665 return FALSE; 01666 for (; l1; l1 = l1->next, l2 = l2->next) 01667 { 01668 if (!guid_equal (l1->data, l2->data)) 01669 return FALSE; 01670 } 01671 return TRUE; 01672 } 01673 01674 QofQueryPredData * 01675 qof_query_choice_predicate (QofGuidMatch options, GList * guid_list) 01676 { 01677 query_choice_t pdata; 01678 GList *node; 01679 01680 if (NULL == guid_list) 01681 return NULL; 01682 01683 pdata = g_new0 (query_choice_def, 1); 01684 pdata->pd.how = QOF_COMPARE_EQUAL; 01685 pdata->pd.type_name = query_choice_type; 01686 pdata->options = options; 01687 01688 pdata->guids = g_list_copy (guid_list); 01689 for (node = pdata->guids; node; node = node->next) 01690 { 01691 GUID *guid = guid_malloc (); 01692 *guid = *((GUID *) node->data); 01693 node->data = guid; 01694 } 01695 return ((QofQueryPredData *) pdata); 01696 } 01697 01698 01699 /* initialization ================================================== */ 01711 static void 01712 qof_query_register_core_object (QofType core_name, 01713 QofQueryPredicateFunc pred, 01714 QofCompareFunc comp, 01715 QueryPredicateCopyFunc copy, 01716 QueryPredDataFree pd_free, 01717 QueryToString toString, QueryPredicateEqual pred_equal) 01718 { 01719 g_return_if_fail (core_name); 01720 g_return_if_fail (*core_name != '\0'); 01721 01722 if (pred) 01723 g_hash_table_insert (predTable, (char *) core_name, pred); 01724 01725 if (comp) 01726 g_hash_table_insert (cmpTable, (char *) core_name, comp); 01727 01728 if (copy) 01729 g_hash_table_insert (copyTable, (char *) core_name, copy); 01730 01731 if (pd_free) 01732 g_hash_table_insert (freeTable, (char *) core_name, pd_free); 01733 01734 if (toString) 01735 g_hash_table_insert (toStringTable, (char *) core_name, toString); 01736 01737 if (pred_equal) 01738 g_hash_table_insert (predEqualTable, (char *) core_name, 01739 pred_equal); 01740 } 01741 01742 static void 01743 init_tables (void) 01744 { 01745 guint i; 01746 struct 01747 { 01748 QofType name; 01749 QofQueryPredicateFunc pred; 01750 QofCompareFunc comp; 01751 QueryPredicateCopyFunc copy; 01752 QueryPredDataFree pd_free; 01753 QueryToString toString; 01754 QueryPredicateEqual pred_equal; 01755 } knownTypes[] = 01756 { 01757 { 01758 QOF_TYPE_STRING, string_match_predicate, string_compare_func, 01759 string_copy_predicate, string_free_pdata, 01760 string_to_string, string_predicate_equal}, 01761 { 01762 QOF_TYPE_TIME, time_match_predicate, time_compare_func, 01763 time_copy_predicate, time_free_pdata, time_to_string, 01764 time_predicate_equal}, 01765 { 01766 QOF_TYPE_DEBCRED, numeric_match_predicate, 01767 numeric_compare_func, numeric_copy_predicate, 01768 numeric_free_pdata, debcred_to_string, 01769 numeric_predicate_equal}, 01770 { 01771 QOF_TYPE_NUMERIC, numeric_match_predicate, 01772 numeric_compare_func, numeric_copy_predicate, 01773 numeric_free_pdata, numeric_to_string, 01774 numeric_predicate_equal}, 01775 { 01776 QOF_TYPE_GUID, guid_match_predicate, NULL, 01777 guid_copy_predicate, guid_free_pdata, NULL, 01778 guid_predicate_equal}, 01779 { 01780 QOF_TYPE_INT32, int32_match_predicate, int32_compare_func, 01781 int32_copy_predicate, int32_free_pdata, 01782 int32_to_string, int32_predicate_equal}, 01783 { 01784 QOF_TYPE_INT64, int64_match_predicate, int64_compare_func, 01785 int64_copy_predicate, int64_free_pdata, 01786 int64_to_string, int64_predicate_equal}, 01787 { 01788 QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func, 01789 double_copy_predicate, double_free_pdata, 01790 double_to_string, double_predicate_equal}, 01791 { 01792 QOF_TYPE_BOOLEAN, boolean_match_predicate, 01793 boolean_compare_func, boolean_copy_predicate, 01794 boolean_free_pdata, boolean_to_string, 01795 boolean_predicate_equal}, 01796 { 01797 QOF_TYPE_CHAR, char_match_predicate, char_compare_func, 01798 char_copy_predicate, char_free_pdata, char_to_string, 01799 char_predicate_equal}, 01800 { 01801 QOF_TYPE_KVP, kvp_match_predicate, NULL, kvp_copy_predicate, 01802 kvp_free_pdata, NULL, kvp_predicate_equal}, 01803 { 01804 QOF_TYPE_COLLECT, collect_match_predicate, 01805 collect_compare_func, collect_copy_predicate, 01806 collect_free_pdata, NULL, collect_predicate_equal}, 01807 { 01808 QOF_TYPE_CHOICE, choice_match_predicate, NULL, 01809 choice_copy_predicate, choice_free_pdata, NULL, 01810 choice_predicate_equal},}; 01811 01812 /* Register the known data types */ 01813 for (i = 0; i < (sizeof (knownTypes) / sizeof (*knownTypes)); i++) 01814 { 01815 qof_query_register_core_object (knownTypes[i].name, 01816 knownTypes[i].pred, 01817 knownTypes[i].comp, 01818 knownTypes[i].copy, 01819 knownTypes[i].pd_free, 01820 knownTypes[i].toString, knownTypes[i].pred_equal); 01821 } 01822 } 01823 01824 static QueryPredicateCopyFunc 01825 qof_query_copy_predicate (QofType type) 01826 { 01827 QueryPredicateCopyFunc rc; 01828 g_return_val_if_fail (type, NULL); 01829 rc = g_hash_table_lookup (copyTable, type); 01830 return rc; 01831 } 01832 01833 static QueryPredDataFree 01834 qof_query_predicate_free (QofType type) 01835 { 01836 g_return_val_if_fail (type, NULL); 01837 return g_hash_table_lookup (freeTable, type); 01838 } 01839 01840 /********************************************************************/ 01841 /* PUBLISHED API FUNCTIONS */ 01842 01843 void 01844 qof_query_core_init (void) 01845 { 01846 /* Only let us initialize once */ 01847 if (initialized) 01848 return; 01849 initialized = TRUE; 01850 01851 /* Create the tables */ 01852 predTable = g_hash_table_new (g_str_hash, g_str_equal); 01853 cmpTable = g_hash_table_new (g_str_hash, g_str_equal); 01854 copyTable = g_hash_table_new (g_str_hash, g_str_equal); 01855 freeTable = g_hash_table_new (g_str_hash, g_str_equal); 01856 toStringTable = g_hash_table_new (g_str_hash, g_str_equal); 01857 predEqualTable = g_hash_table_new (g_str_hash, g_str_equal); 01858 01859 init_tables (); 01860 } 01861 01862 void 01863 qof_query_core_shutdown (void) 01864 { 01865 if (!initialized) 01866 return; 01867 initialized = FALSE; 01868 01869 g_hash_table_destroy (predTable); 01870 g_hash_table_destroy (cmpTable); 01871 g_hash_table_destroy (copyTable); 01872 g_hash_table_destroy (freeTable); 01873 g_hash_table_destroy (toStringTable); 01874 g_hash_table_destroy (predEqualTable); 01875 } 01876 01877 QofQueryPredicateFunc 01878 qof_query_core_get_predicate (QofType type) 01879 { 01880 g_return_val_if_fail (type, NULL); 01881 return g_hash_table_lookup (predTable, type); 01882 } 01883 01884 QofCompareFunc 01885 qof_query_core_get_compare (QofType type) 01886 { 01887 g_return_val_if_fail (type, NULL); 01888 return g_hash_table_lookup (cmpTable, type); 01889 } 01890 01891 void 01892 qof_query_core_predicate_free (QofQueryPredData * pdata) 01893 { 01894 QueryPredDataFree free_fcn; 01895 01896 g_return_if_fail (pdata); 01897 g_return_if_fail (pdata->type_name); 01898 01899 free_fcn = qof_query_predicate_free (pdata->type_name); 01900 free_fcn (pdata); 01901 } 01902 01903 QofQueryPredData * 01904 qof_query_core_predicate_copy (QofQueryPredData * pdata) 01905 { 01906 QueryPredicateCopyFunc copy; 01907 01908 g_return_val_if_fail (pdata, NULL); 01909 g_return_val_if_fail (pdata->type_name, NULL); 01910 01911 copy = qof_query_copy_predicate (pdata->type_name); 01912 return (copy (pdata)); 01913 } 01914 01915 gchar * 01916 qof_query_core_to_string (QofType type, gpointer object, 01917 QofParam * getter) 01918 { 01919 QueryToString toString; 01920 01921 g_return_val_if_fail (type, NULL); 01922 g_return_val_if_fail (object, NULL); 01923 g_return_val_if_fail (getter, NULL); 01924 01925 toString = g_hash_table_lookup (toStringTable, type); 01926 g_return_val_if_fail (toString, NULL); 01927 01928 return toString (object, getter); 01929 } 01930 01931 gboolean 01932 qof_query_core_predicate_equal (QofQueryPredData * p1, 01933 QofQueryPredData * p2) 01934 { 01935 QueryPredicateEqual pred_equal; 01936 01937 if (p1 == p2) 01938 return TRUE; 01939 if (!p1 || !p2) 01940 return FALSE; 01941 01942 if (p1->how != p2->how) 01943 return FALSE; 01944 if (safe_strcmp (p1->type_name, p2->type_name)) 01945 return FALSE; 01946 01947 pred_equal = g_hash_table_lookup (predEqualTable, p1->type_name); 01948 g_return_val_if_fail (pred_equal, FALSE); 01949 01950 return pred_equal (p1, p2); 01951 }