gnucash/libgnucash/engine/qofquerycore.cpp
Geert Janssens 1238b9d8cd Prevent gcc from searching config.h in the current directory
This will avoid a ninja-build from picking up a config.h generated by the autotools build
(in the root build directory). Picking up the wrong config.h may lead to all kinds of
subtle issues if the autotools run was done with different options than the cmake run.
2017-10-26 14:05:17 +02:00

1823 lines
51 KiB
C++

/********************************************************************\
* QueryCore.c -- API for providing core Query data types *
* Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
\********************************************************************/
#include "guid.hpp"
#include <config.h>
#include <glib.h>
#include <stdlib.h>
#include "qof.h"
#include "qofquerycore-p.h"
static QofLogModule log_module = QOF_MOD_QUERY;
/* A function to destroy a query predicate's pdata */
typedef void (*QueryPredDataFree) (QofQueryPredData *pdata);
/* A function to copy a query's predicate data */
typedef QofQueryPredData *(*QueryPredicateCopyFunc) (const QofQueryPredData *pdata);
/* A function to take the object, apply the getter->param_getfcn,
* and return a printable string. Note that this QofParam->getfnc
* function should be returning a type equal to this core object type.
*
* Note that this string MUST be freed by the caller.
*/
typedef char * (*QueryToString) (gpointer object, QofParam *getter);
/* A function to test for equality of predicate data */
typedef gboolean (*QueryPredicateEqual) (const QofQueryPredData *p1,
const QofQueryPredData *p2);
static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type);
static QueryPredDataFree qof_query_predicate_free (QofType type);
/* Core Type Predicate helpers */
typedef const char * (*query_string_getter) (gpointer, QofParam *);
static const char * query_string_type = QOF_TYPE_STRING;
typedef Timespec (*query_date_getter) (gpointer, QofParam *);
static const char * query_date_type = QOF_TYPE_DATE;
typedef gnc_numeric (*query_numeric_getter) (gpointer, QofParam *);
static const char * query_numeric_type = QOF_TYPE_NUMERIC;
typedef GList * (*query_glist_getter) (gpointer, QofParam *);
typedef const GncGUID * (*query_guid_getter) (gpointer, QofParam *);
static const char * query_guid_type = QOF_TYPE_GUID;
typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
static const char * query_int32_type = QOF_TYPE_INT32;
typedef gint64 (*query_int64_getter) (gpointer, QofParam *);
static const char * query_int64_type = QOF_TYPE_INT64;
typedef double (*query_double_getter) (gpointer, QofParam *);
static const char * query_double_type = QOF_TYPE_DOUBLE;
typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
static const char * query_boolean_type = QOF_TYPE_BOOLEAN;
typedef char (*query_char_getter) (gpointer, QofParam *);
static const char * query_char_type = QOF_TYPE_CHAR;
typedef QofCollection * (*query_collect_getter) (gpointer, QofParam*);
static const char * query_collect_type = QOF_TYPE_COLLECT;
typedef const GncGUID * (*query_choice_getter) (gpointer, QofParam *);
static const char * query_choice_type = QOF_TYPE_CHOICE;
/* Tables for predicate storage and lookup */
static gboolean initialized = FALSE;
static GHashTable *predTable = NULL;
static GHashTable *cmpTable = NULL;
static GHashTable *copyTable = NULL;
static GHashTable *freeTable = NULL;
static GHashTable *toStringTable = NULL;
static GHashTable *predEqualTable = NULL;
#define COMPARE_ERROR -3
#define PREDICATE_ERROR -2
#define VERIFY_PDATA(str) { \
g_return_if_fail (pd != NULL); \
g_return_if_fail (pd->type_name == str || \
!g_strcmp0 (str, pd->type_name)); \
}
#define VERIFY_PDATA_R(str) { \
g_return_val_if_fail (pd != NULL, NULL); \
g_return_val_if_fail (pd->type_name == str || \
!g_strcmp0 (str, pd->type_name), \
NULL); \
}
#define VERIFY_PREDICATE(str) { \
g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
g_return_val_if_fail (pd != NULL, PREDICATE_ERROR); \
g_return_val_if_fail (pd->type_name == str || \
!g_strcmp0 (str, pd->type_name), \
PREDICATE_ERROR); \
}
/* *******************************************************************/
/* TYPE-HANDLING FUNCTIONS */
/* QOF_TYPE_STRING */
static int
string_match_predicate (gpointer object,
QofParam *getter,
QofQueryPredData *pd)
{
query_string_t pdata = (query_string_t) pd;
const char *s;
int ret = 0;
VERIFY_PREDICATE (query_string_type);
s = ((query_string_getter)getter->param_getfcn) (object, getter);
if (!s) s = "";
if (pdata->is_regex)
{
regmatch_t match;
if (!regexec (&pdata->compiled, s, 1, &match, 0))
ret = 1;
}
else
{
if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE)
{
if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
{
if (qof_utf8_substr_nocase (s, pdata->matchstring)) //uses strstr
ret = 1;
}
else
{
if (safe_strcasecmp (s, pdata->matchstring) == 0) //uses collate
ret = 1;
}
}
else
{
if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
{
if (strstr (s, pdata->matchstring))
ret = 1;
}
else
{
if (g_strcmp0 (s, pdata->matchstring) == 0)
ret = 1;
}
}
}
switch (pd->how)
{
case QOF_COMPARE_CONTAINS:
return ret;
case QOF_COMPARE_NCONTAINS:
return !ret;
case QOF_COMPARE_EQUAL:
return ret;
case QOF_COMPARE_NEQ:
return !ret;
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
string_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
const char *s1, *s2;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
return safe_strcasecmp (s1, s2);
return g_strcmp0 (s1, s2);
}
int
qof_string_number_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
const char *s1, *s2;
char *sr1, *sr2;
long i1, i2;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
// Deal with NULL strings
if (s1 == s2) return 0;
if (!s1 && s2) return -1;
if (s1 && !s2) return 1;
// Convert to integers and test
i1 = strtol(s1, &sr1, 10);
i2 = strtol(s2, &sr2, 10);
if (i1 < i2) return -1;
if (i1 > i2) return 1;
// If the integers match, then test the REST of the string as text.
if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
return safe_strcasecmp (sr1, sr2);
return g_strcmp0 (sr1, sr2);
}
static void
string_free_pdata (QofQueryPredData *pd)
{
query_string_t pdata = (query_string_t) pd;
VERIFY_PDATA (query_string_type);
if (pdata->is_regex)
regfree (&pdata->compiled);
g_free (pdata->matchstring);
g_free (pdata);
}
static QofQueryPredData *
string_copy_predicate (const QofQueryPredData *pd)
{
const query_string_t pdata = (const query_string_t) pd;
VERIFY_PDATA_R (query_string_type);
return qof_query_string_predicate (pd->how, pdata->matchstring,
pdata->options,
pdata->is_regex);
}
static gboolean
string_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_string_t pd1 = (const query_string_t) p1;
const query_string_t pd2 = (const query_string_t) p2;
if (pd1->options != pd2->options) return FALSE;
if (pd1->is_regex != pd2->is_regex) return FALSE;
return (g_strcmp0 (pd1->matchstring, pd2->matchstring) == 0);
}
QofQueryPredData *
qof_query_string_predicate (QofQueryCompare how,
const char *str, QofStringMatch options,
gboolean is_regex)
{
query_string_t pdata;
g_return_val_if_fail (str, NULL);
// g_return_val_if_fail (*str != '\0', NULL);
g_return_val_if_fail (how == QOF_COMPARE_CONTAINS || how == QOF_COMPARE_NCONTAINS ||
how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, NULL);
pdata = g_new0 (query_string_def, 1);
pdata->pd.type_name = query_string_type;
pdata->pd.how = how;
pdata->options = options;
pdata->matchstring = g_strdup (str);
if (is_regex)
{
int rc;
int flags = REG_EXTENDED;
if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
flags |= REG_ICASE;
rc = regcomp(&pdata->compiled, str, flags);
if (rc)
{
g_free(pdata->matchstring);
g_free(pdata);
return NULL;
}
pdata->is_regex = TRUE;
}
return ((QofQueryPredData*)pdata);
}
static char *
string_to_string (gpointer object, QofParam *getter)
{
const char *res;
res = ((query_string_getter)getter->param_getfcn)(object, getter);
if (res)
return g_strdup (res);
return NULL;
}
/* QOF_TYPE_DATE =================================================== */
static int
date_compare (Timespec ta, Timespec tb, QofDateMatch options)
{
if (options == QOF_DATE_MATCH_DAY)
{
ta = timespecCanonicalDayTime (ta);
tb = timespecCanonicalDayTime (tb);
}
if (ta.tv_sec < tb.tv_sec)
return -1;
if (ta.tv_sec > tb.tv_sec)
return 1;
if (ta.tv_nsec < tb.tv_nsec)
return -1;
if (ta.tv_nsec > tb.tv_nsec)
return 1;
return 0;
}
static int
date_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_date_t pdata = (query_date_t)pd;
Timespec objtime;
int compare;
VERIFY_PREDICATE (query_date_type);
objtime = ((query_date_getter)getter->param_getfcn) (object, getter);
compare = date_compare (objtime, pdata->date, pdata->options);
switch (pd->how)
{
case QOF_COMPARE_LT:
return (compare < 0);
case QOF_COMPARE_LTE:
return (compare <= 0);
case QOF_COMPARE_EQUAL:
return (compare == 0);
case QOF_COMPARE_GT:
return (compare > 0);
case QOF_COMPARE_GTE:
return (compare >= 0);
case QOF_COMPARE_NEQ:
return (compare != 0);
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
Timespec ta, tb;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
ta = ((query_date_getter)getter->param_getfcn) (a, getter);
tb = ((query_date_getter)getter->param_getfcn) (b, getter);
return date_compare (ta, tb, static_cast<QofDateMatch>(options));
}
static void
date_free_pdata (QofQueryPredData *pd)
{
query_date_t pdata = (query_date_t)pd;
VERIFY_PDATA (query_date_type);
g_free (pdata);
}
static QofQueryPredData *
date_copy_predicate (const QofQueryPredData *pd)
{
const query_date_t pdata = (const query_date_t)pd;
VERIFY_PDATA_R (query_date_type);
return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
}
static gboolean
date_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_date_t pd1 = (const query_date_t) p1;
const query_date_t pd2 = (const query_date_t) p2;
if (pd1->options != pd2->options) return FALSE;
return timespec_equal (&(pd1->date), &(pd2->date));
}
QofQueryPredData *
qof_query_date_predicate (QofQueryCompare how,
QofDateMatch options, Timespec date)
{
query_date_t pdata;
pdata = g_new0 (query_date_def, 1);
pdata->pd.type_name = query_date_type;
pdata->pd.how = how;
pdata->options = options;
pdata->date = date;
return ((QofQueryPredData*)pdata);
}
gboolean
qof_query_date_predicate_get_date (const QofQueryPredData *pd, Timespec *date)
{
const query_date_t pdata = (const query_date_t)pd;
if (pdata->pd.type_name != query_date_type)
return FALSE;
*date = pdata->date;
return TRUE;
}
static char *
date_to_string (gpointer object, QofParam *getter)
{
Timespec ts = ((query_date_getter)getter->param_getfcn)(object, getter);
if (ts.tv_sec || ts.tv_nsec)
return g_strdup (gnc_print_date (ts));
return NULL;
}
/* QOF_TYPE_NUMERIC ================================================= */
static int
numeric_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData* pd)
{
query_numeric_t pdata = (query_numeric_t)pd;
gnc_numeric obj_val;
int compare;
VERIFY_PREDICATE (query_numeric_type);
obj_val = ((query_numeric_getter)getter->param_getfcn) (object, getter);
switch (pdata->options)
{
case QOF_NUMERIC_MATCH_CREDIT:
if (gnc_numeric_positive_p (obj_val)) return 0;
break;
case QOF_NUMERIC_MATCH_DEBIT:
if (gnc_numeric_negative_p (obj_val)) return 0;
break;
default:
break;
}
/* Amounts are considered to be 'equal' if they match to
* four decimal places. (epsilon=1/10000) */
if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ)
{
gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
compare =
(gnc_numeric_compare (gnc_numeric_abs
(gnc_numeric_sub (gnc_numeric_abs (obj_val),
gnc_numeric_abs (pdata->amount),
100000, GNC_HOW_RND_ROUND_HALF_UP)),
cmp_val) < 0);
}
else
compare = gnc_numeric_compare (gnc_numeric_abs (obj_val), pdata->amount);
switch (pd->how)
{
case QOF_COMPARE_LT:
return (compare < 0);
case QOF_COMPARE_LTE:
return (compare <= 0);
case QOF_COMPARE_EQUAL:
return compare;
case QOF_COMPARE_GT:
return (compare > 0);
case QOF_COMPARE_GTE:
return (compare >= 0);
case QOF_COMPARE_NEQ:
return !compare;
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
gnc_numeric va, vb;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
return gnc_numeric_compare (va, vb);
}
static void
numeric_free_pdata (QofQueryPredData* pd)
{
query_numeric_t pdata = (query_numeric_t)pd;
VERIFY_PDATA (query_numeric_type);
g_free (pdata);
}
static QofQueryPredData *
numeric_copy_predicate (const QofQueryPredData *pd)
{
const query_numeric_t pdata = (const query_numeric_t)pd;
VERIFY_PDATA_R (query_numeric_type);
return qof_query_numeric_predicate (pd->how, pdata->options, pdata->amount);
}
static gboolean
numeric_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_numeric_t pd1 = (const query_numeric_t) p1;
const query_numeric_t pd2 = (const query_numeric_t) p2;
if (pd1->options != pd2->options) return FALSE;
return gnc_numeric_equal (pd1->amount, pd2->amount);
}
QofQueryPredData *
qof_query_numeric_predicate (QofQueryCompare how,
QofNumericMatch options,
gnc_numeric value)
{
query_numeric_t pdata;
pdata = g_new0 (query_numeric_def, 1);
pdata->pd.type_name = query_numeric_type;
pdata->pd.how = how;
pdata->options = options;
pdata->amount = value;
return ((QofQueryPredData*)pdata);
}
static char *
numeric_to_string (gpointer object, QofParam *getter)
{
gnc_numeric num;
num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
return gnc_numeric_to_string (num);
}
static char *
debcred_to_string (gpointer object, QofParam *getter)
{
gnc_numeric num;
num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
return gnc_numeric_to_string (num);
}
/* QOF_TYPE_GUID =================================================== */
static int
guid_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_guid_t pdata = (query_guid_t)pd;
GList *node, *o_list;
const GncGUID *guid = NULL;
VERIFY_PREDICATE (query_guid_type);
switch (pdata->options)
{
case QOF_GUID_MATCH_ALL:
/* object is a GList of objects; param_getfcn must be called on each one.
* See if every guid in the predicate is accounted-for in the
* object list
*/
for (node = pdata->guids; node; node = node->next)
{
/* See if this GncGUID matches the object's guid */
for (o_list = static_cast<GList*>(object); o_list;
o_list = static_cast<GList*>(o_list->next))
{
guid = ((query_guid_getter)getter->param_getfcn) (o_list->data, getter);
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
break;
}
/*
* If o_list is NULL, we've walked the whole list without finding
* a match. Therefore break out now, the match has failed.
*/
if (o_list == NULL)
break;
}
/*
* The match is complete. If node == NULL then we've successfully
* found a match for all the guids in the predicate. Return
* appropriately below.
*/
break;
case QOF_GUID_MATCH_LIST_ANY:
/* object is a single object, getter returns a GList* of GncGUID*
*
* See if any GncGUID* in the returned list matches any guid in the
* predicate match list.
*/
o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
for (node = o_list; node; node = node->next)
{
GList *node2;
/* Search the predicate data for a match */
for (node2 = pdata->guids; node2; node2 = node2->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data),
static_cast<GncGUID*>(node2->data)))
break;
}
/* Check to see if we found a match. If so, break now */
if (node2 != NULL)
break;
}
g_list_free(o_list);
/* yea, node may point to an invalid location, but that's ok.
* we're not _USING_ the value, just checking that it's non-NULL
*/
break;
default:
/* object is a single object, getter returns a GncGUID*
*
* See if the guid is in the list
*/
guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
for (node = pdata->guids; node; node = node->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
break;
}
}
switch (pdata->options)
{
case QOF_GUID_MATCH_ANY:
case QOF_GUID_MATCH_LIST_ANY:
return (node != NULL);
break;
case QOF_GUID_MATCH_NONE:
case QOF_GUID_MATCH_ALL:
return (node == NULL);
break;
case QOF_GUID_MATCH_NULL:
return ((guid == NULL) || guid_equal(guid, guid_null()));
break;
default:
PWARN ("bad match type");
return 0;
}
}
static void
guid_free_pdata (QofQueryPredData *pd)
{
query_guid_t pdata = (query_guid_t)pd;
GList *node;
VERIFY_PDATA (query_guid_type);
for (node = pdata->guids; node; node = node->next)
{
guid_free (static_cast<GncGUID*>(node->data));
}
g_list_free (pdata->guids);
g_free (pdata);
}
static QofQueryPredData *
guid_copy_predicate (const QofQueryPredData *pd)
{
const query_guid_t pdata = (const query_guid_t)pd;
VERIFY_PDATA_R (query_guid_type);
return qof_query_guid_predicate (pdata->options, pdata->guids);
}
static gboolean
guid_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_guid_t pd1 = (const query_guid_t) p1;
const query_guid_t pd2 = (const query_guid_t) p2;
GList *l1 = pd1->guids, *l2 = pd2->guids;
if (pd1->options != pd2->options) return FALSE;
if (g_list_length (l1) != g_list_length (l2)) return FALSE;
for ( ; l1 ; l1 = l1->next, l2 = l2->next)
{
if (!guid_equal (static_cast<GncGUID*>(l1->data),
static_cast<GncGUID*>(l2->data)))
return FALSE;
}
return TRUE;
}
QofQueryPredData *
qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
{
query_guid_t pdata;
GList *node;
/* An empty list of guids is only valid when testing for a null GUID value */
if (!guid_list)
g_return_val_if_fail (options == QOF_GUID_MATCH_NULL, NULL);
pdata = g_new0 (query_guid_def, 1);
pdata->pd.how = QOF_COMPARE_EQUAL;
pdata->pd.type_name = query_guid_type;
pdata->options = options;
pdata->guids = g_list_copy (guid_list);
for (node = pdata->guids; node; node = node->next)
{
GncGUID *guid = guid_malloc ();
*guid = *((GncGUID *)node->data);
node->data = guid;
}
return ((QofQueryPredData*)pdata);
}
/* ================================================================ */
/* QOF_TYPE_INT32 */
static int
int32_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
gint32 val;
query_int32_t pdata = (query_int32_t)pd;
VERIFY_PREDICATE (query_int32_type);
val = ((query_int32_getter)getter->param_getfcn) (object, getter);
switch (pd->how)
{
case QOF_COMPARE_LT:
return (val < pdata->val);
case QOF_COMPARE_LTE:
return (val <= pdata->val);
case QOF_COMPARE_EQUAL:
return (val == pdata->val);
case QOF_COMPARE_GT:
return (val > pdata->val);
case QOF_COMPARE_GTE:
return (val >= pdata->val);
case QOF_COMPARE_NEQ:
return (val != pdata->val);
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
int32_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
gint32 v1, v2;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
v1 = ((query_int32_getter)getter->param_getfcn)(a, getter);
v2 = ((query_int32_getter)getter->param_getfcn)(b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
static void
int32_free_pdata (QofQueryPredData *pd)
{
query_int32_t pdata = (query_int32_t)pd;
VERIFY_PDATA (query_int32_type);
g_free (pdata);
}
static QofQueryPredData *
int32_copy_predicate (const QofQueryPredData *pd)
{
const query_int32_t pdata = (const query_int32_t)pd;
VERIFY_PDATA_R (query_int32_type);
return qof_query_int32_predicate (pd->how, pdata->val);
}
static gboolean
int32_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_int32_t pd1 = (const query_int32_t) p1;
const query_int32_t pd2 = (const query_int32_t) p2;
return (pd1->val == pd2->val);
}
QofQueryPredData *
qof_query_int32_predicate (QofQueryCompare how, gint32 val)
{
query_int32_t pdata = g_new0 (query_int32_def, 1);
pdata->pd.type_name = query_int32_type;
pdata->pd.how = how;
pdata->val = val;
return ((QofQueryPredData*)pdata);
}
static char *
int32_to_string (gpointer object, QofParam *getter)
{
gint32 num = ((query_int32_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%d", num);
}
/* ================================================================ */
/* QOF_TYPE_INT64 */
static int
int64_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
gint64 val;
query_int64_t pdata = (query_int64_t)pd;
VERIFY_PREDICATE (query_int64_type);
val = ((query_int64_getter)getter->param_getfcn) (object, getter);
switch (pd->how)
{
case QOF_COMPARE_LT:
return (val < pdata->val);
case QOF_COMPARE_LTE:
return (val <= pdata->val);
case QOF_COMPARE_EQUAL:
return (val == pdata->val);
case QOF_COMPARE_GT:
return (val > pdata->val);
case QOF_COMPARE_GTE:
return (val >= pdata->val);
case QOF_COMPARE_NEQ:
return (val != pdata->val);
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
int64_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
gint64 v1, v2;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
v1 = ((query_int64_getter)getter->param_getfcn)(a, getter);
v2 = ((query_int64_getter)getter->param_getfcn)(b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
static void
int64_free_pdata (QofQueryPredData *pd)
{
query_int64_t pdata = (query_int64_t)pd;
VERIFY_PDATA (query_int64_type);
g_free (pdata);
}
static QofQueryPredData *
int64_copy_predicate (const QofQueryPredData *pd)
{
const query_int64_t pdata = (const query_int64_t)pd;
VERIFY_PDATA_R (query_int64_type);
return qof_query_int64_predicate (pd->how, pdata->val);
}
static gboolean
int64_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_int64_t pd1 = (const query_int64_t) p1;
const query_int64_t pd2 = (const query_int64_t) p2;
return (pd1->val == pd2->val);
}
QofQueryPredData *
qof_query_int64_predicate (QofQueryCompare how, gint64 val)
{
query_int64_t pdata = g_new0 (query_int64_def, 1);
pdata->pd.type_name = query_int64_type;
pdata->pd.how = how;
pdata->val = val;
return ((QofQueryPredData*)pdata);
}
static char *
int64_to_string (gpointer object, QofParam *getter)
{
gint64 num = ((query_int64_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%" G_GINT64_FORMAT, num);
}
/* ================================================================ */
/* QOF_TYPE_DOUBLE */
static int
double_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
double val;
query_double_t pdata = (query_double_t)pd;
VERIFY_PREDICATE (query_double_type);
val = ((query_double_getter)getter->param_getfcn) (object, getter);
switch (pd->how)
{
case QOF_COMPARE_LT:
return (val < pdata->val);
case QOF_COMPARE_LTE:
return (val <= pdata->val);
case QOF_COMPARE_EQUAL:
return (val == pdata->val);
case QOF_COMPARE_GT:
return (val > pdata->val);
case QOF_COMPARE_GTE:
return (val >= pdata->val);
case QOF_COMPARE_NEQ:
return (val != pdata->val);
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
double_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
double v1, v2;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
v1 = ((query_double_getter)getter->param_getfcn) (a, getter);
v2 = ((query_double_getter)getter->param_getfcn) (b, getter);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
return 0;
}
static void
double_free_pdata (QofQueryPredData *pd)
{
query_double_t pdata = (query_double_t)pd;
VERIFY_PDATA (query_double_type);
g_free (pdata);
}
static QofQueryPredData *
double_copy_predicate (const QofQueryPredData *pd)
{
const query_double_t pdata = (const query_double_t)pd;
VERIFY_PDATA_R (query_double_type);
return qof_query_double_predicate (pd->how, pdata->val);
}
static gboolean
double_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_double_t pd1 = (const query_double_t) p1;
const query_double_t pd2 = (const query_double_t) p2;
return (pd1->val == pd2->val);
}
QofQueryPredData *
qof_query_double_predicate (QofQueryCompare how, double val)
{
query_double_t pdata = g_new0 (query_double_def, 1);
pdata->pd.type_name = query_double_type;
pdata->pd.how = how;
pdata->val = val;
return ((QofQueryPredData*)pdata);
}
static char *
double_to_string (gpointer object, QofParam *getter)
{
double num = ((query_double_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%f", num);
}
/* QOF_TYPE_BOOLEAN =================================================== */
static int
boolean_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
gboolean val;
query_boolean_t pdata = (query_boolean_t)pd;
VERIFY_PREDICATE (query_boolean_type);
val = ((query_boolean_getter)getter->param_getfcn) (object, getter);
switch (pd->how)
{
case QOF_COMPARE_EQUAL:
return (val == pdata->val);
case QOF_COMPARE_NEQ:
return (val != pdata->val);
default:
PWARN ("bad match type: %d", pd->how);
return 0;
}
}
static int
boolean_compare_func (gpointer a, gpointer b, gint options,
QofParam *getter)
{
gboolean va, vb;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
va = ((query_boolean_getter)getter->param_getfcn) (a, getter);
vb = ((query_boolean_getter)getter->param_getfcn) (b, getter);
if (!va && vb) return -1;
if (va && !vb) return 1;
return 0;
}
static void
boolean_free_pdata (QofQueryPredData *pd)
{
query_boolean_t pdata = (query_boolean_t)pd;
VERIFY_PDATA (query_boolean_type);
g_free (pdata);
}
static QofQueryPredData *
boolean_copy_predicate (const QofQueryPredData *pd)
{
const query_boolean_t pdata = (const query_boolean_t)pd;
VERIFY_PDATA_R (query_boolean_type);
return qof_query_boolean_predicate (pd->how, pdata->val);
}
static gboolean
boolean_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_boolean_t pd1 = (const query_boolean_t) p1;
const query_boolean_t pd2 = (const query_boolean_t) p2;
return (pd1->val == pd2->val);
}
QofQueryPredData *
qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
{
query_boolean_t pdata;
g_return_val_if_fail (how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, NULL);
pdata = g_new0 (query_boolean_def, 1);
pdata->pd.type_name = query_boolean_type;
pdata->pd.how = how;
pdata->val = val;
return ((QofQueryPredData*)pdata);
}
static char *
boolean_to_string (gpointer object, QofParam *getter)
{
gboolean num = ((query_boolean_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%s", (num ? "X" : ""));
}
/* QOF_TYPE_CHAR =================================================== */
static int
char_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
char c;
query_char_t pdata = (query_char_t)pd;
VERIFY_PREDICATE (query_char_type);
c = ((query_char_getter)getter->param_getfcn) (object, getter);
switch (pdata->options)
{
case QOF_CHAR_MATCH_ANY:
if (strchr (pdata->char_list, c)) return 1;
return 0;
case QOF_CHAR_MATCH_NONE:
if (!strchr (pdata->char_list, c)) return 1;
return 0;
default:
PWARN ("bad match type");
return 0;
}
}
static int
char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
char va, vb;
g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
va = ((query_char_getter)getter->param_getfcn)(a, getter);
vb = ((query_char_getter)getter->param_getfcn)(b, getter);
return (va - vb);
}
static void
char_free_pdata (QofQueryPredData *pd)
{
query_char_t pdata = (query_char_t)pd;
VERIFY_PDATA (query_char_type);
g_free (pdata->char_list);
g_free (pdata);
}
static QofQueryPredData *
char_copy_predicate (const QofQueryPredData *pd)
{
const query_char_t pdata = (const query_char_t)pd;
VERIFY_PDATA_R (query_char_type);
return qof_query_char_predicate (pdata->options, pdata->char_list);
}
static gboolean
char_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_char_t pd1 = (const query_char_t) p1;
const query_char_t pd2 = (const query_char_t) p2;
if (pd1->options != pd2->options) return FALSE;
return (g_strcmp0 (pd1->char_list, pd2->char_list) == 0);
}
QofQueryPredData *
qof_query_char_predicate (QofCharMatch options, const char *chars)
{
query_char_t pdata;
g_return_val_if_fail (chars, NULL);
pdata = g_new0 (query_char_def, 1);
pdata->pd.type_name = query_char_type;
pdata->pd.how = QOF_COMPARE_EQUAL;
pdata->options = options;
pdata->char_list = g_strdup (chars);
return ((QofQueryPredData*)pdata);
}
static char *
char_to_string (gpointer object, QofParam *getter)
{
char num = ((query_char_getter)getter->param_getfcn)(object, getter);
return g_strdup_printf ("%c", num);
}
/* QOF_TYPE_COLLECT =============================================== */
static int
collect_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_coll_t pdata;
GList *node, *node2, *o_list;
const GncGUID *guid;
pdata = (query_coll_t)pd;
VERIFY_PREDICATE (query_collect_type);
guid = NULL;
switch (pdata->options)
{
case QOF_GUID_MATCH_ALL :
{
for (node = pdata->guids; node; node = node->next)
{
for (o_list = static_cast<GList*>(object); o_list;
o_list = static_cast<GList*>(o_list->next))
{
guid = ((query_guid_getter)getter->param_getfcn)
(o_list->data, getter);
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
{
break;
}
}
if (o_list == NULL)
{
break;
}
}
break;
}
case QOF_GUID_MATCH_LIST_ANY :
{
o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
for (node = o_list; node; node = node->next)
{
for (node2 = pdata->guids; node2; node2 = node2->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data),
static_cast<GncGUID*>(node2->data)))
{
break;
}
}
if (node2 != NULL)
{
break;
}
}
g_list_free(o_list);
break;
}
default :
{
guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
for (node = pdata->guids; node; node = node->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
{
break;
}
}
}
switch (pdata->options)
{
case QOF_GUID_MATCH_ANY :
case QOF_GUID_MATCH_LIST_ANY :
{
return (node != NULL);
break;
}
case QOF_GUID_MATCH_NONE :
case QOF_GUID_MATCH_ALL :
{
return (node == NULL);
break;
}
case QOF_GUID_MATCH_NULL :
{
return ((guid == NULL) || guid_equal(guid, guid_null()));
break;
}
default :
{
PWARN ("bad match type");
return 0;
}
}
}
return 0;
}
static int
collect_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
{
gint result;
QofCollection *c1, *c2;
c1 = ((query_collect_getter)getter->param_getfcn) (a, getter);
c2 = ((query_collect_getter)getter->param_getfcn) (b, getter);
result = qof_collection_compare(c1, c2);
return result;
}
static void
collect_free_pdata (QofQueryPredData *pd)
{
query_coll_t pdata;
GList *node;
node = NULL;
pdata = (query_coll_t) pd;
VERIFY_PDATA (query_collect_type);
for (node = pdata->guids; node; node = node->next)
{
guid_free (static_cast<GncGUID*>(node->data));
}
qof_collection_destroy(pdata->coll);
g_list_free (pdata->guids);
g_free (pdata);
}
static QofQueryPredData *
collect_copy_predicate (const QofQueryPredData *pd)
{
const query_coll_t pdata = (const query_coll_t) pd;
VERIFY_PDATA_R (query_collect_type);
return qof_query_collect_predicate (pdata->options, pdata->coll);
}
static gboolean
collect_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_coll_t pd1 = (const query_coll_t) p1;
const query_coll_t pd2 = (const query_coll_t) p2;
gint result;
result = qof_collection_compare(pd1->coll, pd2->coll);
if (result == 0)
{
return TRUE;
}
return FALSE;
}
static void
query_collect_cb(QofInstance* ent, gpointer user_data)
{
query_coll_t pdata;
GncGUID *guid;
guid = (GncGUID*)qof_entity_get_guid(ent);
pdata = (query_coll_t)user_data;
pdata->guids = g_list_append(pdata->guids, guid);
}
QofQueryPredData *
qof_query_collect_predicate (QofGuidMatch options, QofCollection *coll)
{
query_coll_t pdata;
g_return_val_if_fail (coll, NULL);
pdata = g_new0 (query_coll_def, 1);
pdata->pd.type_name = query_collect_type;
pdata->options = options;
qof_collection_foreach(coll, query_collect_cb, pdata);
if (NULL == pdata->guids)
{
return NULL;
}
return ((QofQueryPredData*)pdata);
}
/* QOF_TYPE_CHOICE */
static int
choice_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_choice_t pdata = (query_choice_t)pd;
GList *node, *o_list;
const GncGUID *guid = NULL;
VERIFY_PREDICATE (query_choice_type);
switch (pdata->options)
{
case QOF_GUID_MATCH_ALL:
/* object is a GList of objects; param_getfcn must be called on each one.
* See if every guid in the predicate is accounted-for in the
* object list
*/
for (node = pdata->guids; node; node = node->next)
{
/* See if this GncGUID matches the object's guid */
for (o_list = static_cast<GList*>(object); o_list;
o_list = static_cast<GList*>(o_list->next))
{
guid = ((query_choice_getter)getter->param_getfcn) (o_list->data, getter);
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
break;
}
/*
* If o_list is NULL, we've walked the whole list without finding
* a match. Therefore break out now, the match has failed.
*/
if (o_list == NULL)
break;
}
/*
* The match is complete. If node == NULL then we've successfully
* found a match for all the guids in the predicate. Return
* appropriately below.
*/
break;
case QOF_GUID_MATCH_LIST_ANY:
o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
for (node = o_list; node; node = node->next)
{
GList *node2;
for (node2 = pdata->guids; node2; node2 = node2->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data),
static_cast<GncGUID*>(node2->data)))
break;
}
if (node2 != NULL)
break;
}
g_list_free(o_list);
break;
default:
/* object is a single object, getter returns a GncGUID*
*
* See if the guid is in the list
*/
guid = ((query_choice_getter)getter->param_getfcn) (object, getter);
for (node = pdata->guids; node; node = node->next)
{
if (guid_equal (static_cast<GncGUID*>(node->data), guid))
break;
}
}
switch (pdata->options)
{
case QOF_GUID_MATCH_ANY:
case QOF_GUID_MATCH_LIST_ANY:
return (node != NULL);
break;
case QOF_GUID_MATCH_NONE:
case QOF_GUID_MATCH_ALL:
return (node == NULL);
break;
case QOF_GUID_MATCH_NULL:
return ((guid == NULL) || guid_equal(guid, guid_null()));
break;
default:
PWARN ("bad match type");
return 0;
}
}
static void
choice_free_pdata (QofQueryPredData *pd)
{
query_choice_t pdata = (query_choice_t)pd;
GList *node;
VERIFY_PDATA (query_choice_type);
for (node = pdata->guids; node; node = node->next)
{
guid_free (static_cast<GncGUID*>(node->data));
}
g_list_free (pdata->guids);
g_free (pdata);
}
static QofQueryPredData *
choice_copy_predicate (const QofQueryPredData *pd)
{
const query_choice_t pdata = (const query_choice_t)pd;
VERIFY_PDATA_R (query_choice_type);
return qof_query_choice_predicate (pdata->options, pdata->guids);
}
static gboolean
choice_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
const query_choice_t pd1 = (const query_choice_t) p1;
const query_choice_t pd2 = (const query_choice_t) p2;
GList *l1 = pd1->guids, *l2 = pd2->guids;
if (pd1->options != pd2->options) return FALSE;
if (g_list_length (l1) != g_list_length (l2)) return FALSE;
for ( ; l1 ; l1 = l1->next, l2 = l2->next)
{
if (!guid_equal (static_cast<GncGUID*>(l1->data),
static_cast<GncGUID*>(l2->data)))
return FALSE;
}
return TRUE;
}
QofQueryPredData *
qof_query_choice_predicate (QofGuidMatch options, GList *guid_list)
{
query_choice_t pdata;
GList *node;
if (NULL == guid_list) return NULL;
pdata = g_new0 (query_choice_def, 1);
pdata->pd.how = QOF_COMPARE_EQUAL;
pdata->pd.type_name = query_choice_type;
pdata->options = options;
pdata->guids = g_list_copy (guid_list);
for (node = pdata->guids; node; node = node->next)
{
GncGUID *guid = guid_malloc ();
*guid = *((GncGUID *)node->data);
node->data = guid;
}
return ((QofQueryPredData*)pdata);
}
/* initialization ================================================== */
/** This function registers a new Core Object with the QofQuery
* subsystem. It maps the "core_name" object to the given
* query_predicate, predicate_copy, and predicate_data_free functions.
*
* An example:
* qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
* string_compare_fcn, string_free_pdata,
* string_print_fcn, pred_equal_fcn);
*/
static void
qof_query_register_core_object (QofType core_name,
QofQueryPredicateFunc pred,
QofCompareFunc comp,
QueryPredicateCopyFunc copy,
QueryPredDataFree pd_free,
QueryToString toString,
QueryPredicateEqual pred_equal)
{
g_return_if_fail (core_name);
g_return_if_fail (*core_name != '\0');
if (pred)
g_hash_table_insert (predTable, (char *)core_name,
reinterpret_cast<void*>(pred));
if (comp)
g_hash_table_insert (cmpTable, (char *)core_name,
reinterpret_cast<void*>(comp));
if (copy)
g_hash_table_insert (copyTable, (char *)core_name,
reinterpret_cast<void*>(copy));
if (pd_free)
g_hash_table_insert (freeTable, (char *)core_name,
reinterpret_cast<void*>(pd_free));
if (toString)
g_hash_table_insert (toStringTable, (char *)core_name,
reinterpret_cast<void*>(toString));
if (pred_equal)
g_hash_table_insert (predEqualTable, (char *)core_name,
reinterpret_cast<void*>(pred_equal));
}
static void init_tables (void)
{
unsigned int i;
struct
{
QofType name;
QofQueryPredicateFunc pred;
QofCompareFunc comp;
QueryPredicateCopyFunc copy;
QueryPredDataFree pd_free;
QueryToString toString;
QueryPredicateEqual pred_equal;
} knownTypes[] =
{
{
QOF_TYPE_STRING, string_match_predicate, string_compare_func,
string_copy_predicate, string_free_pdata, string_to_string,
string_predicate_equal
},
{
QOF_TYPE_DATE, date_match_predicate, date_compare_func,
date_copy_predicate, date_free_pdata, date_to_string,
date_predicate_equal
},
{
QOF_TYPE_DEBCRED, numeric_match_predicate, numeric_compare_func,
numeric_copy_predicate, numeric_free_pdata, debcred_to_string,
numeric_predicate_equal
},
{
QOF_TYPE_NUMERIC, numeric_match_predicate, numeric_compare_func,
numeric_copy_predicate, numeric_free_pdata, numeric_to_string,
numeric_predicate_equal
},
{
QOF_TYPE_GUID, guid_match_predicate, NULL,
guid_copy_predicate, guid_free_pdata, NULL,
guid_predicate_equal
},
{
QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
int32_copy_predicate, int32_free_pdata, int32_to_string,
int32_predicate_equal
},
{
QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
int64_copy_predicate, int64_free_pdata, int64_to_string,
int64_predicate_equal
},
{
QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
double_copy_predicate, double_free_pdata, double_to_string,
double_predicate_equal
},
{
QOF_TYPE_BOOLEAN, boolean_match_predicate, boolean_compare_func,
boolean_copy_predicate, boolean_free_pdata, boolean_to_string,
boolean_predicate_equal
},
{
QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
char_copy_predicate, char_free_pdata, char_to_string,
char_predicate_equal
},
{
QOF_TYPE_COLLECT, collect_match_predicate, collect_compare_func,
collect_copy_predicate, collect_free_pdata, NULL,
collect_predicate_equal
},
{
QOF_TYPE_CHOICE, choice_match_predicate, NULL,
choice_copy_predicate, choice_free_pdata, NULL, choice_predicate_equal
},
};
/* Register the known data types */
for (i = 0; i < (sizeof(knownTypes) / sizeof(*knownTypes)); i++)
{
qof_query_register_core_object (knownTypes[i].name,
knownTypes[i].pred,
knownTypes[i].comp,
knownTypes[i].copy,
knownTypes[i].pd_free,
knownTypes[i].toString,
knownTypes[i].pred_equal);
}
}
static QueryPredicateCopyFunc
qof_query_copy_predicate (QofType type)
{
QueryPredicateCopyFunc rc;
g_return_val_if_fail (type, NULL);
rc = reinterpret_cast<QueryPredicateCopyFunc>(g_hash_table_lookup (copyTable, type));
return rc;
}
static QueryPredDataFree
qof_query_predicate_free (QofType type)
{
g_return_val_if_fail (type, NULL);
return reinterpret_cast<QueryPredDataFree>(g_hash_table_lookup (freeTable, type));
}
/********************************************************************/
/* PUBLISHED API FUNCTIONS */
void qof_query_core_init (void)
{
/* Only let us initialize once */
if (initialized) return;
initialized = TRUE;
/* Create the tables */
predTable = g_hash_table_new (g_str_hash, g_str_equal);
cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
copyTable = g_hash_table_new (g_str_hash, g_str_equal);
freeTable = g_hash_table_new (g_str_hash, g_str_equal);
toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
init_tables ();
}
void qof_query_core_shutdown (void)
{
if (!initialized) return;
initialized = FALSE;
g_hash_table_destroy (predTable);
g_hash_table_destroy (cmpTable);
g_hash_table_destroy (copyTable);
g_hash_table_destroy (freeTable);
g_hash_table_destroy (toStringTable);
g_hash_table_destroy (predEqualTable);
}
QofQueryPredicateFunc
qof_query_core_get_predicate (QofType type)
{
g_return_val_if_fail (type, NULL);
return reinterpret_cast<QofQueryPredicateFunc>(g_hash_table_lookup (predTable, type));
}
QofCompareFunc
qof_query_core_get_compare (QofType type)
{
g_return_val_if_fail (type, NULL);
return reinterpret_cast<QofCompareFunc>(g_hash_table_lookup (cmpTable, type));
}
void
qof_query_core_predicate_free (QofQueryPredData *pdata)
{
QueryPredDataFree free_fcn;
g_return_if_fail (pdata);
g_return_if_fail (pdata->type_name);
free_fcn = qof_query_predicate_free (pdata->type_name);
free_fcn (pdata);
}
QofQueryPredData *
qof_query_core_predicate_copy (const QofQueryPredData *pdata)
{
QueryPredicateCopyFunc copy;
g_return_val_if_fail (pdata, NULL);
g_return_val_if_fail (pdata->type_name, NULL);
copy = qof_query_copy_predicate (pdata->type_name);
return (copy (pdata));
}
char *
qof_query_core_to_string (QofType type, gpointer object,
QofParam *getter)
{
QueryToString toString;
g_return_val_if_fail (type, NULL);
g_return_val_if_fail (object, NULL);
g_return_val_if_fail (getter, NULL);
toString = reinterpret_cast<QueryToString>(g_hash_table_lookup (toStringTable, type));
g_return_val_if_fail (toString, NULL);
return toString (object, getter);
}
gboolean
qof_query_core_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
{
QueryPredicateEqual pred_equal;
if (p1 == p2) return TRUE;
if (!p1 || !p2) return FALSE;
if (p1->how != p2->how) return FALSE;
if (g_strcmp0 (p1->type_name, p2->type_name)) return FALSE;
pred_equal = reinterpret_cast<QueryPredicateEqual>(g_hash_table_lookup (predEqualTable, p1->type_name));
g_return_val_if_fail (pred_equal, FALSE);
return pred_equal (p1, p2);
}