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

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4