qofquerycore.c

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

Generated on Fri Sep 1 15:37:32 2006 for QOF by  doxygen 1.4.6