gnucash/libgnucash/engine/qofquerycore.cpp
Robert Fewell 8bd7deb3dc Reapply filter when number of sub-accounts change
When viewing a register that displays sub-accounts, if the number of
sub-accounts is changed, the query is rebuilt from the remaining
sub-accounts but when a filter is being used it is not applied after.

Fixed by checking the original query for a filter and if so applying
that after query rebuilt.
2024-06-27 10:03:22 +01:00

1832 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 time64 (*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 = nullptr;
static GHashTable *cmpTable = nullptr;
static GHashTable *copyTable = nullptr;
static GHashTable *freeTable = nullptr;
static GHashTable *toStringTable = nullptr;
static GHashTable *predEqualTable = nullptr;
#define COMPARE_ERROR -3
#define PREDICATE_ERROR -2
#define VERIFY_PDATA(str) { \
g_return_if_fail (pd != nullptr); \
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 != nullptr, nullptr); \
g_return_val_if_fail (pd->type_name == str || \
!g_strcmp0 (str, pd->type_name), \
nullptr); \
}
#define VERIFY_PREDICATE(str) { \
g_return_val_if_fail (getter != nullptr, PREDICATE_ERROR); \
g_return_val_if_fail (getter->param_getfcn != nullptr, PREDICATE_ERROR); \
g_return_val_if_fail (pd != nullptr, 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 nullptr 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, nullptr);
// g_return_val_if_fail (*str != '\0', nullptr);
g_return_val_if_fail (how == QOF_COMPARE_CONTAINS || how == QOF_COMPARE_NCONTAINS ||
how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, nullptr);
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 nullptr;
}
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 nullptr;
}
/* QOF_TYPE_DATE =================================================== */
static int
date_compare (time64 ta, time64 tb, QofDateMatch options)
{
if (options == QOF_DATE_MATCH_DAY)
{
ta = time64CanonicalDayTime (ta);
tb = time64CanonicalDayTime (tb);
}
if (ta < tb)
return -1;
if (ta > tb)
return 1;
return 0;
}
static int
date_match_predicate (gpointer object, QofParam *getter,
QofQueryPredData *pd)
{
query_date_t pdata = (query_date_t)pd;
time64 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)
{
time64 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 (pd1->date == pd2->date);
}
QofQueryPredData *
qof_query_date_predicate (QofQueryCompare how,
QofDateMatch options, time64 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, time64 *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)
{
time64 tt = ((query_date_getter)getter->param_getfcn)(object, getter);
if (tt != INT64_MAX)
return qof_print_date (tt);
return nullptr;
}
/* 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 = nullptr;
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 nullptr, we've walked the whole list without finding
* a match. Therefore break out now, the match has failed.
*/
if (o_list == nullptr)
break;
}
/*
* The match is complete. If node == nullptr 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 != nullptr)
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-nullptr
*/
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 != nullptr);
break;
case QOF_GUID_MATCH_NONE:
case QOF_GUID_MATCH_ALL:
return (node == nullptr);
break;
case QOF_GUID_MATCH_NULL:
return ((guid == nullptr) || 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;
for (; l1 || l2; l1 = l1->next, l2 = l2->next)
{
if (!l1 || !l2)
return FALSE;
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, nullptr);
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, nullptr);
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, nullptr);
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);
}
gboolean
qof_query_char_predicate_get_char (const QofQueryPredData *pd, char **chars)
{
const query_char_t pdata = (const query_char_t)pd;
if (pdata->pd.type_name != query_char_type)
return FALSE;
*chars = g_strdup (pdata->char_list);
return TRUE;
}
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 = nullptr;
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 == nullptr)
{
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 != nullptr)
{
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 != nullptr);
break;
}
case QOF_GUID_MATCH_NONE :
case QOF_GUID_MATCH_ALL :
{
return (node == nullptr);
break;
}
case QOF_GUID_MATCH_NULL :
{
return ((guid == nullptr) || 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 = nullptr;
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, nullptr);
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 (nullptr == pdata->guids)
{
return nullptr;
}
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 = nullptr;
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 nullptr, we've walked the whole list without finding
* a match. Therefore break out now, the match has failed.
*/
if (o_list == nullptr)
break;
}
/*
* The match is complete. If node == nullptr 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 != nullptr)
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 != nullptr);
break;
case QOF_GUID_MATCH_NONE:
case QOF_GUID_MATCH_ALL:
return (node == nullptr);
break;
case QOF_GUID_MATCH_NULL:
return ((guid == nullptr) || 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;
for (; l1 || l2; l1 = l1->next, l2 = l2->next)
{
if (!l1 || !l2)
return FALSE;
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 (nullptr == guid_list) return nullptr;
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, nullptr,
guid_copy_predicate, guid_free_pdata, nullptr,
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, nullptr,
collect_predicate_equal
},
{
QOF_TYPE_CHOICE, choice_match_predicate, nullptr,
choice_copy_predicate, choice_free_pdata, nullptr, 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, nullptr);
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, nullptr);
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, nullptr);
return reinterpret_cast<QofQueryPredicateFunc>(g_hash_table_lookup (predTable, type));
}
QofCompareFunc
qof_query_core_get_compare (QofType type)
{
g_return_val_if_fail (type, nullptr);
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, nullptr);
g_return_val_if_fail (pdata->type_name, nullptr);
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, nullptr);
g_return_val_if_fail (object, nullptr);
g_return_val_if_fail (getter, nullptr);
toString = reinterpret_cast<QueryToString>(g_hash_table_lookup (toStringTable, type));
g_return_val_if_fail (toString, nullptr);
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);
}