GnuCash 2.4.99
qofquerycore.c
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines