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