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

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4