[Gnucash-changes] Changes: Synchronize with QOF cvs tree.
Linas Vepstas
linas at cvs.gnucash.org
Sun May 2 23:33:45 EDT 2004
Log Message:
-----------
Changes:
Synchronize with QOF cvs tree.
gnc-engine-util.h:
-- add string utility to remove whitespace
-- add string utility that recognizess booleans 'TRUE', 'true' etc
guid.h:
kvp_frame.h:
-- doc clarification
qofclass.c:
qofclass.h:
-- fix core dump
-- add qof_class_is_registered() inquiry
qofgobj.c:
-- fix whitespace/bad indentation
qofquery.c:
-- fix query printing
-- fix buglet when mergeing two queries, and one is empty
qofquerycore.c:
-- some subroutine arguments should be const
-- add a handy-dandy qof_query_kvp_predicate_path() convenience routine
qofquerycore.h:
-- fix whitespace/bad indentation
qofsql.c:
qofsql.h:
-- add support for KVP in SQL queries
-- fix problems with GUID's in sql queries
-- separate query parse step from the query execute step
qofquery-serialize.c
qofquery-serialize.h
qofquery-deserial.c
qofquery-deserial.h:
-- Add new functions to turn a query into XML and back.
(Oh, don't ask why, needed for a gnomevfs integration stunt)
Modified Files:
--------------
gnucash/src/engine:
gnc-engine-util.c
gnc-engine-util.h
guid.c
guid.h
kvp_frame.h
qofclass.c
qofclass.h
qofgobj.c
qofquery.c
qofquery.h
qofquerycore.c
qofquerycore.h
qofsession.c
qofsql.c
qofsql.h
Added Files:
-----------
gnucash/src/engine:
qofquery-deserial.c
qofquery-deserial.h
qofquery-serialize.c
qofquery-serialize.h
Revision Data
-------------
Index: qofsql.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsql.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lsrc/engine/qofsql.h -Lsrc/engine/qofsql.h -u -r1.3 -r1.4
--- src/engine/qofsql.h
+++ src/engine/qofsql.h
@@ -34,6 +34,7 @@
#include <glib.h>
#include <qof/kvp_frame.h>
#include <qof/qofbook.h>
+#include <qof/qofquery.h>
typedef struct _QofSqlQuery QofSqlQuery;
@@ -49,6 +50,7 @@
void qof_sql_query_set_book (QofSqlQuery *q, QofBook *book);
/** Perform the query, return the results.
+ * The book must be set in order to be able to perform a query.
*
* The returned list is a list of ... See below ...
* The returned list will have been sorted using the indicated sort
@@ -69,6 +71,14 @@
* together with parenthesis can be used to construct arbitrarily
* nested predicates.
*
+ * If the param is a KVP frame, then we use a special markup to
+ * indicate frame values. The markup should look like
+ * /some/kvp/path:value. Thus, for example,
+ * SELECT * FROM SomeObj WHERE (param_a < '/some/kvp:10.0')
+ * will search for the object where param_a is a KVP frame, and this
+ * KVP frame contains a path '/some/kvp' and the value stored at that
+ * path is floating-point and that float value is less than 10.0.
+ *
* The following are types of queries are NOT supported:
* SELECT a,b,c FROM ...
* I am thinking of implementing the above as a list of KVP's
@@ -85,6 +95,23 @@
*/
GList * qof_sql_query_run (QofSqlQuery *query, const char * str);
+
+/** Same as above, but just parse/pre-process the query; do
+ * not actually run it over the dataset. The QofBook does not
+ * need to be set before calling this function.
+ */
+void qof_sql_query_parse (QofSqlQuery *query, const char * str);
+
+/** Return the QofQuery form of the previously parsed query. */
+QofQuery * qof_sql_query_get_query (QofSqlQuery *);
+
+/** Run the previously parsed query. The QofBook must be set
+ * before this function can be called. Note, teh QofBook can
+ * be changed between each successive call to this routine.
+ * This routine can be called after either qof_sql_query_parse()
+ * or qof_sql_query_run() because both will set up the parse.
+ */
+GList * qof_sql_query_rerun (QofSqlQuery *query);
/**
* Set the kvp frame to be used for formulating 'indirect' predicates.
Index: qofquery.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -Lsrc/engine/qofquery.h -Lsrc/engine/qofquery.h -u -r1.8 -r1.9
--- src/engine/qofquery.h
+++ src/engine/qofquery.h
@@ -188,8 +188,8 @@
*/
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op);
-/** Like qof_query_merge, but this will merge q2 into q1. q2 remains
- * unchanged.
+/** Like qof_query_merge, but this will merge a copy of q2 into q1.
+ * q2 remains unchanged.
*/
void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op);
Index: qofquery.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquery.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -Lsrc/engine/qofquery.c -Lsrc/engine/qofquery.c -u -r1.22 -r1.23
--- src/engine/qofquery.c
+++ src/engine/qofquery.c
@@ -1,5 +1,5 @@
/********************************************************************\
- * QofQuery.c -- API for finding Gnucash objects *
+ * qof_query.c -- Implement predicate API for searching for objects *
* Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU> *
* *
* This program is free software; you can redistribute it and/or *
@@ -958,7 +958,7 @@
retval->max_results = q->max_results;
break;
- /* this is demorgan expansion for a single AND expression. */
+ /* This is the DeMorgan expansion for a single AND expression. */
/* !(abc) = !a + !b + !c */
case 1:
retval = qof_query_create();
@@ -975,7 +975,7 @@
new_oterm = g_list_append(NULL, qt);
/* g_list_append() can take forever, so let's do this for speed
- * in "large" queries
+ * in "large" queries.
*/
retval->terms = g_list_reverse(retval->terms);
retval->terms = g_list_prepend(retval->terms, new_oterm);
@@ -983,7 +983,7 @@
}
break;
- /* if there are multiple OR-terms, we just recurse by
+ /* If there are multiple OR-terms, we just recurse by
* breaking it down to !(a + b + c) =
* !a * !(b + c) = !a * !b * !c. */
default:
@@ -1000,7 +1000,7 @@
retval = qof_query_merge(iright, ileft, QOF_QUERY_AND);
retval->books = g_list_copy (q->books);
retval->max_results = q->max_results;
- retval->search_for = q->search_for;
+ retval->search_for = q->search_for;
retval->changed = 1;
qof_query_destroy(iright);
@@ -1037,6 +1037,20 @@
search_for = (q1->search_for ? q1->search_for : q2->search_for);
+ /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty.
+ * The goal of this tweak is to all the user to start with
+ * an empty q1 and then append to it recursively
+ * (and q1 (and q2 (and q3 (and q4 ....))))
+ * without bombing out because the append started with an
+ * empty list.
+ * We do essentially the same check in qof_query_add_term()
+ * so that the first term added to an empty query doesn't screw up.
+ */
+ if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1)))
+ {
+ op = QOF_QUERY_OR;
+ }
+
switch(op)
{
case QOF_QUERY_OR:
@@ -1214,6 +1228,12 @@
qof_book_get_guid(book), QOF_QUERY_AND);
}
+GList * qof_query_get_books (QofQuery *q)
+{
+ if (!q) return NULL;
+ return q->books;
+}
+
void qof_query_add_boolean_match (QofQuery *q, GSList *param_list, gboolean value,
QofQueryOp op)
{
@@ -1374,6 +1394,7 @@
}
/***************************************************************************/
+/***************************************************************************/
/* Query Print functions. qof_query_print is public; everthing else supports
* that.
* Just call qof_query_print(QofQuery *q), and it will print out the query
@@ -1465,7 +1486,7 @@
searchFor = qof_query_get_search_for (query);
gs = g_string_new ("Query Object Type: ");
- g_string_append (gs, searchFor);
+ g_string_append (gs, (NULL == searchFor)? "(null)" : searchFor);
output = g_list_append (output, gs);
return output;
@@ -1510,7 +1531,7 @@
static GList *
qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
{
- GSList *gsl = NULL;
+ GSList *gsl, *n = NULL;
gint curSort;
GString *gs = g_string_new (" Sort Parameters:\n");
@@ -1523,14 +1544,19 @@
}
increasing = qof_query_sort_get_increasing (s[curSort]);
- for (gsl = qof_query_sort_get_param_path (s[curSort]); gsl; gsl = gsl->next)
+ gsl = qof_query_sort_get_param_path (s[curSort]);
+ if (gsl) g_string_sprintfa (gs, " Param: ");
+ for (n=gsl; n; n = n->next)
{
- GString *sortParm = g_string_new (gsl->data);
- g_string_sprintfa (gs, " Param: %s %s\n", sortParm->str,
- increasing ? "DESC" : "ASC");
- g_string_free (sortParm, TRUE);
+ QofIdType param_name = n->data;
+ if (gsl != n)g_string_sprintfa (gs, "\n ");
+ g_string_sprintfa (gs, "%s", param_name);
+ }
+ if (gsl)
+ {
+ g_string_sprintfa (gs, " %s\n", increasing ? "DESC" : "ASC");
+ g_string_sprintfa (gs, " Options: 0x%x\n", s[curSort]->options);
}
- /* TODO: finish this for loop */
}
output = g_list_append (output, gs);
@@ -1560,6 +1586,8 @@
path = qof_query_term_get_param_path (qt);
invert = qof_query_term_is_inverted (qt);
+ if (invert) output = g_list_append (output,
+ g_string_new(" INVERT SENSE "));
output = g_list_append (output, qof_query_printParamPath (path));
output = g_list_append (output, qof_query_printPredData (pd));
output = g_list_append (output, g_string_new("\n"));
@@ -1597,8 +1625,14 @@
gs = g_string_new (" Pred Data:\n ");
g_string_append (gs, (gchar *) pd->type_name);
- g_string_sprintfa (gs, "\n how: %s",
- qof_query_printStringForHow (pd->how));
+
+ /* Char Predicate and GUID predicate dosn't use the 'how' field. */
+ if (safe_strcmp (pd->type_name, QOF_TYPE_CHAR) &&
+ safe_strcmp (pd->type_name, QOF_TYPE_GUID))
+ {
+ g_string_sprintfa (gs, "\n how: %s",
+ qof_query_printStringForHow (pd->how));
+ }
qof_query_printValueForParam (pd, gs);
@@ -1673,11 +1707,15 @@
{
GSList *node;
query_kvp_t pdata = (query_kvp_t) pd;
+ g_string_sprintfa (gs, "\n kvp path: ");
for (node = pdata->path; node; node = node->next)
{
- g_string_sprintfa (gs, "\n kvp path: %s", (gchar *) node->data);
- return;
+ g_string_sprintfa (gs, "/%s", (gchar *) node->data);
}
+ g_string_sprintfa (gs, "\n");
+ g_string_sprintfa (gs, " kvp value: %s\n",
+ kvp_value_to_string (pdata->value));
+ return;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
{
@@ -1694,7 +1732,7 @@
if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
{
query_double_t pdata = (query_double_t) pd;
- g_string_sprintfa (gs, " double: %20.16g", pdata->val);
+ g_string_sprintfa (gs, " double: %.18g", pdata->val);
return;
}
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
@@ -1816,8 +1854,4 @@
return "UNKNOWN MATCH TYPE";
} /* qof_query_printGuidMatch */
-GList * qof_query_get_books (QofQuery *q)
-{
- if (!q) return NULL;
- return q->books;
-}
+/* ======================== END OF FILE =================== */
Index: qofquerycore.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -Lsrc/engine/qofquerycore.h -Lsrc/engine/qofquerycore.h -u -r1.12 -r1.13
--- src/engine/qofquerycore.h
+++ src/engine/qofquerycore.h
@@ -1,5 +1,5 @@
/********************************************************************\
- * qofquerycore.h -- API for providing core Query data types *
+ * qofquerycore.h -- API for providing core Query data types *
* Copyright (C) 2002 Derek Atkins <warlord at MIT.EDU> *
* *
* This program is free software; you can redistribute it and/or *
@@ -114,28 +114,40 @@
/** Core Data Type Predicates */
-QofQueryPredData *qof_query_string_predicate (QofQueryCompare how, char *str,
- QofStringMatch options,
- gboolean is_regex);
+QofQueryPredData *qof_query_string_predicate (QofQueryCompare how,
+ const char *str,
+ QofStringMatch options,
+ gboolean is_regex);
+
QofQueryPredData *qof_query_date_predicate (QofQueryCompare how,
- QofDateMatch options, Timespec date);
+ QofDateMatch options,
+ Timespec date);
+
QofQueryPredData *qof_query_numeric_predicate (QofQueryCompare how,
- QofNumericMatch options,
- gnc_numeric value);
+ QofNumericMatch options,
+ gnc_numeric value);
+
QofQueryPredData *qof_query_guid_predicate (QofGuidMatch options, GList *guids);
QofQueryPredData *qof_query_int32_predicate (QofQueryCompare how, gint32 val);
QofQueryPredData *qof_query_int64_predicate (QofQueryCompare how, gint64 val);
QofQueryPredData *qof_query_double_predicate (QofQueryCompare how, double val);
QofQueryPredData *qof_query_boolean_predicate (QofQueryCompare how, gboolean val);
QofQueryPredData *qof_query_char_predicate (QofCharMatch options,
- const char *chars);
+ const char *chars);
/** The qof_query_kvp_predicate() matches the object that has
* the value 'value' located at the path 'path'. In a certain
* sense, the 'path' is handled as if it were a paramter.
*/
QofQueryPredData *qof_query_kvp_predicate (QofQueryCompare how,
- GSList *path, const KvpValue *value);
+ GSList *path,
+ const KvpValue *value);
+
+/** Same predicate as above, except that 'path' is assumed to be
+ * a string containing slash-separated pathname. */
+QofQueryPredData *qof_query_kvp_predicate_path (QofQueryCompare how,
+ const char *path,
+ const KvpValue *value);
/** Copy a predicate. */
QofQueryPredData *qof_query_core_predicate_copy (QofQueryPredData *pdata);
Index: qofquerycore.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofquerycore.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -Lsrc/engine/qofquerycore.c -Lsrc/engine/qofquerycore.c -u -r1.13 -r1.14
--- src/engine/qofquerycore.c
+++ src/engine/qofquerycore.c
@@ -219,7 +219,7 @@
QofQueryPredData *
qof_query_string_predicate (QofQueryCompare how,
- char *str, QofStringMatch options,
+ const char *str, QofStringMatch options,
gboolean is_regex)
{
query_string_t pdata;
@@ -656,16 +656,19 @@
}
QofQueryPredData *
-qof_query_guid_predicate (QofGuidMatch options, GList *guids)
+qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
{
query_guid_t pdata;
GList *node;
+ if (NULL == guid_list) return 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 (guids);
+
+ pdata->guids = g_list_copy (guid_list);
for (node = pdata->guids; node; node = node->next)
{
GUID *guid = guid_malloc ();
@@ -1226,6 +1229,33 @@
node->data = g_strdup (node->data);
return ((QofQueryPredData*)pdata);
+}
+
+QofQueryPredData *
+qof_query_kvp_predicate_path (QofQueryCompare how,
+ const char *path, const KvpValue *value)
+{
+ QofQueryPredData *pd;
+ GSList *spath = NULL;
+ char *str, *p;
+
+ if (!path) return NULL;
+
+ str = g_strdup (path);
+ p = str;
+ if (0 == *p) return NULL;
+ if ('/' == *p) p++;
+
+ while (p)
+ {
+ spath = g_slist_append (spath, p);
+ p = strchr (p, '/');
+ if (p) { *p = 0; p++; }
+ }
+
+ pd = qof_query_kvp_predicate (how, spath, value);
+ g_free (str);
+ return pd;
}
/* initialization ================================================== */
Index: qofsql.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsql.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -Lsrc/engine/qofsql.c -Lsrc/engine/qofsql.c -u -r1.4 -r1.5
--- src/engine/qofsql.c
+++ src/engine/qofsql.c
@@ -27,6 +27,8 @@
*/
+#include <stdlib.h> /* for working atoll */
+
#include <glib.h>
#include <libsql/sql_parser.h>
#include <qof/kvp_frame.h>
@@ -36,7 +38,9 @@
#include <qof/guid.h>
#include <qof/qofbook.h>
#include <qof/qofquery.h>
+#include <qof/qofquerycore.h>
#include <qof/qofsql.h>
+#include <qof/gnc-engine-util.h>
static short module = MOD_QUERY;
@@ -56,7 +60,7 @@
QofSqlQuery *
qof_sql_query_new(void)
{
- QofSqlQuery * sqn = (QofSqlQuery *) g_new (QofSqlQuery, 1);
+ QofSqlQuery * sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
sqn->qof_query = NULL;
sqn->parse_result = NULL;
@@ -80,6 +84,15 @@
/* ========================================================== */
+QofQuery *
+qof_sql_query_get_query (QofSqlQuery *q)
+{
+ if (!q) return NULL;
+ return q->qof_query;
+}
+
+/* ========================================================== */
+
void
qof_sql_query_set_book (QofSqlQuery *q, QofBook *book)
{
@@ -96,41 +109,6 @@
q->kvp_join = kvp;
}
-/* =================================================================== */
-/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)
- * Else return pointer to first non-whitespace character. */
-
-static const char *
-whitespace_filter (const char * val)
-{
- size_t len;
- if (!val) return NULL;
-
- len = strspn (val, "\a\b\t\n\v\f\r ");
- if (0 == val[len]) return NULL;
- return val+len;
-}
-
-/* =================================================================== */
-/* Return integer 1 if the string starts with 't' or 'T" or contians the
- * word 'true' or 'TRUE'; if string is a number, return that number. */
-
-static int
-util_bool_to_int (const char * val)
-{
- const char * p = whitespace_filter (val);
- if (!p) return 0;
- if ('t' == p[0]) return 1;
- if ('T' == p[0]) return 1;
- if ('y' == p[0]) return 1;
- if ('Y' == p[0]) return 1;
- if (strstr (p, "true")) return 1;
- if (strstr (p, "TRUE")) return 1;
- if (strstr (p, "yes")) return 1;
- if (strstr (p, "YES")) return 1;
- return atoi (val);
-}
-
/* ========================================================== */
static inline void
@@ -218,7 +196,7 @@
return NULL;
}
qvalue_name = dequote_string (qvalue_name);
- qvalue_name = whitespace_filter (qvalue_name);
+ qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
/* Look to see if its the special KVP value holder.
* If it is, look up the value. */
@@ -305,9 +283,20 @@
PWARN ("Need to specify an object class to query");
return NULL;
}
-
+
+ if (FALSE == qof_class_is_registered (table_name))
+ {
+ PWARN ("The query object \'%s\' is not known", table_name);
+ return NULL;
+ }
+
QofType param_type = qof_class_get_parameter_type (table_name, param_name);
- if (!param_type) return NULL; /* Can't happen */
+ if (!param_type)
+ {
+ PWARN ("The parameter \'%s\' on object \'%s\' is not known",
+ param_name, table_name);
+ return NULL;
+ }
if (!strcmp (param_type, QOF_TYPE_STRING))
{
@@ -319,7 +308,9 @@
}
else if (!strcmp (param_type, QOF_TYPE_CHAR))
{
- pred_data = qof_query_char_predicate (qop, qvalue_name);
+ QofCharMatch cm = QOF_CHAR_MATCH_ANY;
+ if (QOF_COMPARE_NEQ == qop) cm = QOF_CHAR_MATCH_NONE;
+ pred_data = qof_query_char_predicate (cm, qvalue_name);
}
else if (!strcmp (param_type, QOF_TYPE_INT32))
{
@@ -338,7 +329,7 @@
}
else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
{
- gboolean ival = util_bool_to_int (qvalue_name);
+ gboolean ival = qof_util_bool_to_int (qvalue_name);
pred_data = qof_query_boolean_predicate (qop, ival);
}
else if (!strcmp (param_type, QOF_TYPE_DATE))
@@ -375,29 +366,89 @@
}
else if (!strcmp (param_type, QOF_TYPE_GUID))
{
- GUID *guid = guid_malloc();
- gboolean rc = string_to_guid (qvalue_name, guid);
+ GUID guid;
+ gboolean rc = string_to_guid (qvalue_name, &guid);
if (0 == rc)
{
PWARN ("unable to parse guid: %s", qvalue_name);
return NULL;
}
- // XXX match any means eqal, what about not equal ??
// XXX less, than greater than don't make sense,
// should check for those bad conditions
- GList *guid_list = g_list_append (NULL, guid);
- pred_data = qof_query_guid_predicate (QOF_GUID_MATCH_ANY, guid_list);
- // XXX FIXME the above is a memory leak! we leak both guid and glist.
+
+ QofGuidMatch gm = QOF_GUID_MATCH_ANY;
+ if (QOF_COMPARE_NEQ == qop) gm = QOF_GUID_MATCH_NONE;
+ GList *guid_list = g_list_append (NULL, &guid);
+ pred_data = qof_query_guid_predicate (gm, guid_list);
+
+ g_list_free (guid_list);
}
-#if 0
else if (!strcmp (param_type, QOF_TYPE_KVP))
{
-xxxxxhd
- xxxx gboolean ival =
- pred_data = qof_query_kvp_predicate (qop, ival);
+ /* We are expecting an encoded value that looks like
+ * /some/path/string:value
+ */
+ char *sep = strchr (qvalue_name, ':');
+ if (!sep) return NULL;
+ *sep = 0;
+ char * path = qvalue_name;
+ char * str = sep +1;
+ char * p;
+ /* If str has only digits, we know its a plain number.
+ * If its numbers and a decimal point, assume a float
+ * If its numbers and a slash, assume numeric
+ * If its 32 bytes of hex, assume GUID
+ * If it looks like an iso date ...
+ * else assume its a string.
+ */
+ KvpValue *kval = NULL;
+ int len = strlen (str);
+ if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
+ {
+ GUID guid;
+ string_to_guid (str, &guid);
+ kval = kvp_value_new_guid (&guid);
+ }
+ else
+ if (len == strspn (str, "0123456789"))
+ {
+ kval = kvp_value_new_gint64 (atoll(str));
+ }
+ else
+ if ((p=strchr (str, '.')) &&
+ ((len-1) == (strspn (str, "0123456789") +
+ strspn (p+1, "0123456789"))))
+ {
+ kval = kvp_value_new_double (atof(str));
+ }
+
+ else
+ if ((p=strchr (str, '/')) &&
+ ((len-1) == (strspn (str, "0123456789") +
+ strspn (p+1, "0123456789"))))
+ {
+ gnc_numeric num;
+ string_to_gnc_numeric (str, &num);
+ kval = kvp_value_new_gnc_numeric (num);
+ }
+ else
+ if ((p=strchr (str, '-')) &&
+ (p=strchr (p+1, '-')) &&
+ (p=strchr (p+1, ' ')) &&
+ (p=strchr (p+1, ':')) &&
+ (p=strchr (p+1, ':')))
+ {
+ kval = kvp_value_new_timespec (gnc_iso8601_to_timespec_gmt(str));
+ }
+
+ /* The default handler is a string */
+ if (NULL == kval)
+ {
+ kval = kvp_value_new_string (str);
+ }
+ pred_data = qof_query_kvp_predicate_path (qop, path, kval);
}
-#endif
else
{
PWARN ("The predicate type \"%s\" is unsupported for now", param_type);
@@ -505,25 +556,33 @@
/* ========================================================== */
-GList *
-qof_sql_query_run (QofSqlQuery *query, const char *str)
+void
+qof_sql_query_parse (QofSqlQuery *query, const char *str)
{
- GList *node;
+ if (!query) return;
- if (!query) return NULL;
+ /* Delete old query, if any */
+ /* XXX FIXME we should also delete the parse_result as well */
+ if (query->qof_query)
+ {
+ qof_query_destroy (query->qof_query);
+ query->qof_query = NULL;
+ }
+
+ /* Parse the SQL string */
query->parse_result = sql_parse (str);
if (!query->parse_result)
{
PWARN ("parse error");
- return NULL;
+ return;
}
if (SQL_select != query->parse_result->type)
{
PWARN("currently, only SELECT statements are supported, "
"got type=%d", query->parse_result);
- return NULL;
+ return;
}
/* If the user wrote "SELECT * FROM tablename WHERE ..."
@@ -543,7 +602,7 @@
{
/* Walk over the where terms, turn them into QOF predicates */
query->qof_query = handle_where (query, swear);
- if (NULL == query->qof_query) return NULL;
+ if (NULL == query->qof_query) return;
}
else
{
@@ -559,6 +618,37 @@
* XXX all this needs fixing.
*/
qof_query_search_for (query->qof_query, query->single_global_tablename);
+}
+
+/* ========================================================== */
+
+GList *
+qof_sql_query_run (QofSqlQuery *query, const char *str)
+{
+ GList *node;
+
+ if (!query) return NULL;
+
+ qof_sql_query_parse (query, str);
+ if (NULL == query->qof_query) return NULL;
+
+ qof_query_set_book (query->qof_query, query->book);
+
+ // qof_query_print (query->qof_query);
+ GList *results = qof_query_run (query->qof_query);
+
+ return results;
+}
+
+GList *
+qof_sql_query_rerun (QofSqlQuery *query)
+{
+ GList *node;
+
+ if (!query) return NULL;
+
+ if (NULL == query->qof_query) return NULL;
+
qof_query_set_book (query->qof_query, query->book);
// qof_query_print (query->qof_query);
Index: guid.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/guid.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -Lsrc/engine/guid.c -Lsrc/engine/guid.c -u -r1.32 -r1.33
--- src/engine/guid.c
+++ src/engine/guid.c
@@ -89,6 +89,7 @@
GUID *
guid_malloc (void)
{
+ if (!guid_memchunk) guid_memchunk_init();
return g_chunk_new (GUID, guid_memchunk);
}
--- /dev/null
+++ src/engine/qofquery-deserial.c
@@ -0,0 +1,719 @@
+/********************************************************************\
+ * qofquery-deserial.c -- Convert Qof-Query XML to QofQuery *
+ * Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 *
+ * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
+ * Boston, MA 02111-1307, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+// #include "config.h"
+
+#include <stdlib.h>
+#include <glib.h>
+#include <libxml/parser.h>
+
+#include "qofquery-deserial.h"
+#include "qofquery-serialize.h"
+#include "qofquery-p.h"
+#include "qofquerycore-p.h"
+#include "gnc-engine-util.h"
+
+#define CACHE_INSERT(str) \
+ g_cache_insert(gnc_engine_get_string_cache(), (gpointer)(str))
+#define CACHE_REMOVE(str) \
+ g_cache_remove(gnc_engine_get_string_cache(), (gpointer)(str))
+
+/* =========================================================== */
+
+#define GET_TEXT(node) ({ \
+ char * sstr = NULL; \
+ xmlNodePtr text; \
+ text = node->xmlChildrenNode; \
+ if (text && 0 == strcmp ("text", text->name)) { \
+ sstr = text->content; \
+ } \
+ sstr; \
+})
+
+#define GET_STR(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ FN (SELF, str); \
+ } \
+ else
+
+#define GET_DBL(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ double rate = atof (str); \
+ FN (SELF, rate); \
+ } \
+ else
+
+#define GET_INT32(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gint32 ival = atoi (str); \
+ FN (SELF, ival); \
+ } \
+ else
+
+#define GET_INT64(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gint64 ival = atoll (str); \
+ FN (SELF, ival); \
+ } \
+ else
+
+#define GET_DATE(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ Timespec tval = gnc_iso8601_to_timespec_gmt (str); \
+ FN (SELF, tval); \
+ } \
+ else
+
+#define GET_BOOL(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gboolean bval = qof_util_bool_to_int (str); \
+ FN (SELF, bval); \
+ } \
+ else
+
+#define GET_NUMERIC(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ gnc_numeric nval; \
+ string_to_gnc_numeric (str, &nval); \
+ FN (SELF, nval); \
+ } \
+ else
+
+#define GET_GUID(SELF,FN,TOK) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ GUID guid; \
+ string_to_guid (str, &guid); \
+ FN (SELF, &guid); \
+ } \
+ else
+
+#define GET_HOW(VAL,TOK,A,B,C,D,E,F) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_COMPARE_##A; \
+ if (!strcmp (#A, str)) ival = QOF_COMPARE_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_COMPARE_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_COMPARE_##C; \
+ else if (!strcmp (#D, str)) ival = QOF_COMPARE_##D; \
+ else if (!strcmp (#E, str)) ival = QOF_COMPARE_##E; \
+ else if (!strcmp (#F, str)) ival = QOF_COMPARE_##F; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH2(VAL,TOK,PFX,A,B) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH3(VAL,TOK,PFX,A,B,C) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_##PFX##_##C; \
+ VAL = ival; \
+ } \
+ else
+
+#define GET_MATCH5(VAL,TOK,PFX,A,B,C,D,E) \
+ if (0 == strcmp (TOK, node->name)) \
+ { \
+ const char *str = GET_TEXT (node); \
+ int ival = QOF_##PFX##_##A; \
+ if (!strcmp (#A, str)) ival = QOF_##PFX##_##A; \
+ else if (!strcmp (#B, str)) ival = QOF_##PFX##_##B; \
+ else if (!strcmp (#C, str)) ival = QOF_##PFX##_##C; \
+ else if (!strcmp (#D, str)) ival = QOF_##PFX##_##D; \
+ else if (!strcmp (#E, str)) ival = QOF_##PFX##_##E; \
+ VAL = ival; \
+ } \
+ else
+
+/* =============================================================== */
+/* Autogen the code for the simple, repetitive predicates */
+
+#define SIMPLE_PRED_HANDLER(SUBRNAME,CTYPE,GETTER,XMLTYPE,PRED) \
+static QofQueryPredData * \
+SUBRNAME (xmlNodePtr root) \
+{ \
+ xmlNodePtr xp = root->xmlChildrenNode; \
+ xmlNodePtr node; \
+ \
+ QofQueryCompare how = QOF_COMPARE_EQUAL; \
+ CTYPE val = 0; \
+ \
+ for (node=xp; node; node = node->next) \
+ { \
+ if (node->type != XML_ELEMENT_NODE) continue; \
+ \
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ); \
+ GETTER (0, val=, XMLTYPE); \
+ {} \
+ } \
+ \
+ QofQueryPredData *pred; \
+ pred = PRED (how, val); \
+ return pred; \
+}
+
+SIMPLE_PRED_HANDLER (qof_query_pred_double_from_xml,
+ double,
+ GET_DBL,
+ "qofquery:double",
+ qof_query_double_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_int64_from_xml,
+ gint64,
+ GET_INT64,
+ "qofquery:int64",
+ qof_query_int64_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_int32_from_xml,
+ gint32,
+ GET_INT32,
+ "qofquery:int32",
+ qof_query_int32_predicate);
+
+SIMPLE_PRED_HANDLER (qof_query_pred_boolean_from_xml,
+ gboolean,
+ GET_BOOL,
+ "qofquery:boolean",
+ qof_query_boolean_predicate);
+
+/* =============================================================== */
+
+static void wrap_new_gint64(KvpValue **v, gint64 value) {
+ *v = kvp_value_new_gint64 (value); }
+static void wrap_new_double(KvpValue **v, double value) {
+ *v = kvp_value_new_double (value); }
+static void wrap_new_numeric(KvpValue **v, gnc_numeric value) {
+ *v = kvp_value_new_gnc_numeric (value); }
+static void wrap_new_string(KvpValue **v, const char * value) {
+ *v = kvp_value_new_string (value); }
+static void wrap_new_guid(KvpValue **v, const GUID * value) {
+ *v = kvp_value_new_guid (value); }
+static void wrap_new_timespec(KvpValue **v, Timespec value) {
+ *v = kvp_value_new_timespec (value); }
+
+
+static QofQueryPredData *
+qof_query_pred_kvp_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ GSList *path = NULL;
+ KvpValue *value = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ if (0 == strcmp ("qofquery:kvp-path", node->name))
+ {
+ const char *str = GET_TEXT (node);
+ path = g_slist_append (path, (gpointer) str);
+ }
+ else
+ GET_INT64(&value, wrap_new_gint64, "qofquery:int64");
+ GET_DBL(&value, wrap_new_double, "qofquery:double");
+ GET_NUMERIC(&value, wrap_new_numeric, "qofquery:numeric");
+ GET_STR(&value, wrap_new_string, "qofquery:string");
+ GET_GUID(&value, wrap_new_guid, "qofquery:guid");
+ GET_DATE(&value, wrap_new_timespec, "qofquery:date");
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_kvp_predicate (how, path, value);
+ g_slist_free (path);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_guid_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+ GList *guid_list = NULL;
+
+ QofGuidMatch sm = QOF_GUID_MATCH_ANY;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ /* char pred doesn't have GET_HOW */
+ GET_MATCH5 (sm, "qofquery:guid-match",
+ GUID_MATCH, ANY, NONE, NULL, ALL, LIST_ANY);
+
+ if (0 == strcmp ("qofquery:guid", node->name))
+ {
+ const char *str = GET_TEXT (node);
+ GUID *guid = guid_malloc ();
+ gboolean decode = string_to_guid (str, guid);
+ if (decode)
+ {
+ guid_list = g_list_append (guid_list, guid);
+ }
+ else
+ {
+ guid_free (guid);
+ // XXX error! let someone know!
+ }
+ }
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_guid_predicate (sm, guid_list);
+
+ /* The predicate made a copy of everything, so free our stuff */
+ GList *n;
+ for (n=guid_list; n; n=n->next)
+ {
+ guid_free (n->data);
+ }
+ g_list_free (guid_list);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_char_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofCharMatch sm = QOF_CHAR_MATCH_ANY;
+ const char * char_list = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ /* char pred doesn't have GET_HOW */
+ GET_MATCH2 (sm, "qofquery:char-match",
+ CHAR_MATCH, ANY, NONE);
+ GET_STR (0, char_list=, "qofquery:char-list");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_char_predicate (sm, char_list);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_numeric_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofNumericMatch sm = QOF_NUMERIC_MATCH_ANY;
+ gnc_numeric num;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_MATCH3 (sm, "qofquery:numeric-match",
+ NUMERIC_MATCH, DEBIT, CREDIT, ANY);
+ GET_NUMERIC (0, num=, "qofquery:numeric");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_numeric_predicate (how, sm, num);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_date_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofDateMatch sm = QOF_DATE_MATCH_ROUNDED;
+ Timespec date = {0,0};
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_MATCH2 (sm, "qofquery:date-match",
+ DATE_MATCH, NORMAL, ROUNDED);
+ GET_DATE (0, date=, "qofquery:date");
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_date_predicate (how, sm, date);
+ return pred;
+}
+
+/* =============================================================== */
+
+static QofQueryPredData *
+qof_query_pred_string_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr xp = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ QofQueryCompare how = QOF_COMPARE_EQUAL;
+ QofStringMatch sm = QOF_STRING_MATCH_CASEINSENSITIVE;
+ gboolean is_regex = FALSE;
+ const char *pstr = NULL;
+
+ for (node=xp; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_HOW (how, "qofquery:compare", LT, LTE, EQUAL, GT, GTE, NEQ);
+ GET_BOOL (0, is_regex=, "qofquery:is-regex");
+ GET_STR (0, pstr=, "qofquery:string");
+ GET_MATCH2 (sm, "qofquery:string-match",
+ STRING_MATCH, NORMAL, CASEINSENSITIVE);
+ {}
+ }
+
+ QofQueryPredData *pred;
+ pred = qof_query_string_predicate (how, pstr, sm , is_regex);
+ return pred;
+}
+
+/* =============================================================== */
+
+static GSList *
+qof_query_param_path_from_xml (xmlNodePtr root)
+{
+ xmlNodePtr pterms = root->xmlChildrenNode;
+ GSList *plist = NULL;
+ xmlNodePtr node;
+ for (node=pterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:param"))
+ {
+ const char *str = GET_TEXT (node);
+ plist = g_slist_append (plist, CACHE_INSERT(str));
+ }
+ }
+ return plist;
+}
+
+/* =============================================================== */
+
+static void
+qof_query_term_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr node;
+ xmlNodePtr term = root->xmlChildrenNode;
+ QofQueryPredData *pred = NULL;
+ GSList *path = NULL;
+
+ for (node=term; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+ if (0 == strcmp (node->name, "qofquery:invert"))
+ {
+ QofQuery *qt = qof_query_create();
+ qof_query_term_from_xml (qt, node);
+ QofQuery *qinv = qof_query_invert (qt);
+ qof_query_merge_in_place (q, qinv, QOF_QUERY_AND);
+ qof_query_destroy (qinv);
+ qof_query_destroy (qt);
+ return;
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:param-path"))
+ {
+ path = qof_query_param_path_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-string"))
+ {
+ pred = qof_query_pred_string_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-date"))
+ {
+ pred = qof_query_pred_date_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-numeric"))
+ {
+ pred = qof_query_pred_numeric_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-int32"))
+ {
+ pred = qof_query_pred_int32_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-int64"))
+ {
+ pred = qof_query_pred_int64_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-double"))
+ {
+ pred = qof_query_pred_double_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-boolean"))
+ {
+ pred = qof_query_pred_boolean_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-char"))
+ {
+ pred = qof_query_pred_char_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-guid"))
+ {
+ pred = qof_query_pred_guid_from_xml (node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:pred-kvp"))
+ {
+ pred = qof_query_pred_kvp_from_xml (node);
+ }
+ else
+ {
+ // warning unhandled predicate type
+ }
+ }
+
+ /* At this level, the terms should always be anded */
+ qof_query_add_term (q, path, pred, QOF_QUERY_AND);
+}
+
+/* =============================================================== */
+
+static void
+qof_query_and_terms_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr andterms = root->xmlChildrenNode;
+ xmlNodePtr node;
+ for (node=andterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:term"))
+ {
+ qof_query_term_from_xml (q, node);
+ }
+ }
+}
+
+/* =============================================================== */
+
+static void
+qof_query_or_terms_from_xml (QofQuery *q, xmlNodePtr root)
+{
+ xmlNodePtr andterms = root->xmlChildrenNode;
+ xmlNodePtr node;
+
+ for (node=andterms; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ if (0 == strcmp (node->name, "qofquery:and-terms"))
+ {
+ QofQuery *qand = qof_query_create ();
+ qof_query_and_terms_from_xml (qand, node);
+ qof_query_merge_in_place (q, qand, QOF_QUERY_OR);
+ qof_query_destroy (qand);
+ }
+ }
+}
+
+/* =============================================================== */
+
+QofQuery *
+qof_query_from_xml (xmlNodePtr root)
+{
+ QofQuery *q;
+
+ if (!root) return NULL;
+
+ xmlChar * version = xmlGetProp(root, "version");
+ if (!root->name || strcmp ("qof:qofquery", root->name))
+ {
+ // XXX something is wrong. warn ...
+ return NULL;
+ }
+
+ q = qof_query_create ();
+
+ xmlNodePtr qpart = root->xmlChildrenNode;
+ xmlNodePtr node;
+ for (node=qpart; node; node = node->next)
+ {
+ if (node->type != XML_ELEMENT_NODE) continue;
+
+ GET_STR (q, qof_query_search_for, "qofquery:search-for");
+ GET_INT32 (q, qof_query_set_max_results, "qofquery:max-results");
+ if (0 == strcmp (node->name, "qofquery:or-terms"))
+ {
+ qof_query_or_terms_from_xml (q, node);
+ }
+ else
+ if (0 == strcmp (node->name, "qofquery:sort-list"))
+ {
+// XXX unfinished I'm bored
+ }
+ else
+ {
+ // XXX unknown node type tell someone about it
+ }
+ }
+
+ return q;
+}
+
+/* =============================================================== */
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <qof/qofsql.h>
+
+int main (int argc, char * argv[])
+{
+ QofQuery *q, *qnew;
+ QofSqlQuery *sq;
+
+ guid_init();
+ qof_query_init();
+ qof_object_initialize ();
+
+ static QofParam params[] = {
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "aint", QOF_TYPE_INT32, NULL, NULL},
+ { "aint64", QOF_TYPE_INT64, NULL, NULL},
+ { "aflt", QOF_TYPE_DOUBLE, NULL, NULL},
+ { "abool", QOF_TYPE_BOOLEAN, NULL, NULL},
+ { "astr", QOF_TYPE_STRING, NULL, NULL},
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "anum", QOF_TYPE_NUMERIC, NULL, NULL},
+ { "achar", QOF_TYPE_CHAR, NULL, NULL},
+ { "aguid", QOF_TYPE_GUID, NULL, NULL},
+ { "akvp", QOF_TYPE_KVP, NULL, NULL},
+ { NULL },
+ };
+
+ qof_class_register ("GncABC", NULL, params);
+ sq = qof_sql_query_new();
+
+ qof_sql_query_parse (sq,
+ "SELECT * from GncABC WHERE aint = 123 "
+ "and not aint64 = 6123123456789 "
+ "or abool = TRUE "
+ "and not aflt >= \'3.14159265358979\' "
+ "and not astr=\'asdf\' "
+ "and adate<\'01-01-01\' "
+ "or anum<\'12301/100\' "
+ "or achar != asdf "
+ "and aguid != abcdef01234567890fedcba987654321 "
+ "and akvp != \'/some/path:abcdef01234567890fedcba987654321\' "
+ "and not akvp != \'/some/path/glop:1234\' "
+ "and akvp = \'/arf/arf/arf:10.234\' "
+ "and akvp != \'/some/other/path:qwerty1234uiop\' "
+ "and not akvp = \'/some/final/path:123401/100\' "
+ );
+ // qof_sql_query_parse (sq, "SELECT * from GncABC;");
+ q = qof_sql_query_get_query (sq);
+
+ qof_query_print (q);
+
+ xmlNodePtr topnode = qof_query_to_xml (q);
+
+ qnew = qof_query_from_xml (topnode);
+ printf (" ------------------------------------------------------- \n");
+ qof_query_print (qnew);
+
+ /* If the before and after trees are the same, the test pases. */
+ gboolean eq = qof_query_equal (q, qnew);
+ printf ("Are the two equal? answer=%d\n", eq);
+
+#define DOPRINT 1
+#ifdef DOPRINT
+ xmlDocPtr doc = doc = xmlNewDoc("1.0");
+ xmlDocSetRootElement(doc,topnode);
+
+ xmlChar *xbuf;
+ int bufsz;
+ xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
+
+ printf ("%s\n", xbuf);
+ xmlFree (xbuf);
+ xmlFreeDoc(doc);
+#endif
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
+
+/* ======================== END OF FILE =================== */
Index: gnc-engine-util.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine-util.h,v
retrieving revision 1.41
retrieving revision 1.42
diff -Lsrc/engine/gnc-engine-util.h -Lsrc/engine/gnc-engine-util.h -u -r1.41 -r1.42
--- src/engine/gnc-engine-util.h
+++ src/engine/gnc-engine-util.h
@@ -25,7 +25,7 @@
@brief GnuCash engine utility functions
@author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
@author Copyright (C) 2000 Bill Gribble <grib at billgribble.com>
- @author Copyright (C) 1997-2002 Linas Vepstas <linas at linas.org>
+ @author Copyright (C) 1997-2002,2004 Linas Vepstas <linas at linas.org>
*/
#ifndef QOF_UTIL_H
@@ -67,42 +67,50 @@
/** Prototypes *************************************************/
-/* The safe_strcmp compares strings a and b the same way that strcmp()
+/** The safe_strcmp compares strings a and b the same way that strcmp()
* does, except that either may be null. This routine assumes that
* a non-null string is always greater than a null string.
*/
int safe_strcmp (const char * da, const char * db);
int safe_strcasecmp (const char * da, const char * db);
-/* The null_strcmp compares strings a and b the same way that strcmp()
+/** The null_strcmp compares strings a and b the same way that strcmp()
* does, except that either may be null. This routine assumes that
* a null string is equal to the empty string.
*/
int null_strcmp (const char * da, const char * db);
-/* Search for str2 in first nchar chars of str1, ignore case. Return
+/** Search for str2 in first nchar chars of str1, ignore case. Return
* pointer to first match, or null. These are just like that strnstr
* and the strstr functions, except that they ignore the case. */
extern char *strncasestr(const char *str1, const char *str2, size_t len);
extern char *strcasestr(const char *str1, const char *str2);
-/* The ultostr() subroutine is the inverse of strtoul(). It accepts a
+/** The ultostr() subroutine is the inverse of strtoul(). It accepts a
* number and prints it in the indicated base. The returned string
* should be g_freed when done. */
char * ultostr (unsigned long val, int base);
-/* Returns true if string s is a number, possibly surrounded by
+/** Returns true if string s is a number, possibly surrounded by
* whitespace. */
gboolean gnc_strisnum(const char *s);
-/* Define a gnucash stpcpy */
+/** Local copy of stpcpy, used wtih libc's that don't have one. */
char * gnc_stpcpy (char *dest, const char *src);
#ifndef HAVE_STPCPY
#define stpcpy gnc_stpcpy
#endif
+/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)
+ * Else return pointer to first non-whitespace character.
+ */
+const char * qof_util_whitespace_filter (const char * val);
+/** Return integer 1 if the string starts with 't' or 'T' or
+ * contains the word 'true' or 'TRUE'; if string is a number,
+ * return that number. (Leading whitespace is ignored). */
+int qof_util_bool_to_int (const char * val);
/** Many strings used throughout the engine are likely to be duplicated.
* So we provide a reference counted cache system for the strings, which
Index: gnc-engine-util.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-engine-util.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -Lsrc/engine/gnc-engine-util.c -Lsrc/engine/gnc-engine-util.c -u -r1.33 -r1.34
--- src/engine/gnc-engine-util.c
+++ src/engine/gnc-engine-util.c
@@ -1,7 +1,7 @@
/********************************************************************\
* gnc-engine-util.c -- GnuCash engine utility functions *
* Copyright (C) 1997 Robin D. Clark *
- * Copyright (C) 1997-2001 Linas Vepstas <linas at linas.org> *
+ * Copyright (C) 1997-2001,2004 Linas Vepstas <linas at linas.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -177,6 +177,41 @@
{
strcpy (dest, src);
return (dest + strlen (src));
+}
+
+/* =================================================================== */
+/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)
+ * Else return pointer to first non-whitespace character. */
+
+const char *
+qof_util_whitespace_filter (const char * val)
+{
+ size_t len;
+ if (!val) return NULL;
+
+ len = strspn (val, "\a\b\t\n\v\f\r ");
+ if (0 == val[len]) return NULL;
+ return val+len;
+}
+
+/* =================================================================== */
+/* Return integer 1 if the string starts with 't' or 'T' or contains the
+ * word 'true' or 'TRUE'; if string is a number, return that number. */
+
+int
+qof_util_bool_to_int (const char * val)
+{
+ const char * p = qof_util_whitespace_filter (val);
+ if (!p) return 0;
+ if ('t' == p[0]) return 1;
+ if ('T' == p[0]) return 1;
+ if ('y' == p[0]) return 1;
+ if ('Y' == p[0]) return 1;
+ if (strstr (p, "true")) return 1;
+ if (strstr (p, "TRUE")) return 1;
+ if (strstr (p, "yes")) return 1;
+ if (strstr (p, "YES")) return 1;
+ return atoi (val);
}
/********************************************************************\
Index: qofgobj.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofgobj.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lsrc/engine/qofgobj.c -Lsrc/engine/qofgobj.c -u -r1.1 -r1.2
--- src/engine/qofgobj.c
+++ src/engine/qofgobj.c
@@ -49,9 +49,9 @@
// gobjectClassTable = g_hash_table_new (g_str_hash, g_str_equal);
- /* Init the other subsystems that we need */
- qof_object_initialize();
- qof_query_init ();
+ /* Init the other subsystems that we need */
+ qof_object_initialize();
+ qof_query_init ();
}
void
@@ -60,12 +60,12 @@
if (!initialized) return;
initialized = FALSE;
- GSList *n;
- for (n=paramList; n; n=n->next) g_free(n->data);
- g_slist_free (paramList);
+ GSList *n;
+ for (n=paramList; n; n=n->next) g_free(n->data);
+ g_slist_free (paramList);
- for (n=classList; n; n=n->next) g_free(n->data);
- g_slist_free (classList);
+ for (n=classList; n; n=n->next) g_free(n->data);
+ g_slist_free (classList);
#if 0
// XXX also need to walk over books, and collection and delete
@@ -83,13 +83,13 @@
void
qof_gobject_register_instance (QofBook *book, QofType type, GObject *gob)
{
- if (!book || !type) return;
+ if (!book || !type) return;
- QofCollection *coll = qof_book_get_collection (book, type);
+ QofCollection *coll = qof_book_get_collection (book, type);
- GSList * instance_list = qof_collection_get_data (coll);
- instance_list = g_slist_prepend (instance_list, gob);
- qof_collection_set_data (coll, instance_list);
+ GSList * instance_list = qof_collection_get_data (coll);
+ instance_list = g_slist_prepend (instance_list, gob);
+ qof_collection_set_data (coll, instance_list);
}
/* =================================================================== */
@@ -97,91 +97,91 @@
static gpointer
qof_gobject_getter (gpointer data, QofParam *getter)
{
- GObject *gob = data;
+ GObject *gob = data;
- GParamSpec *gps = getter->param_userdata;
+ GParamSpec *gps = getter->param_userdata;
- /* Note that the return type must actually be of type
- * getter->param_type but we just follow the hard-coded
- * mapping below ... */
- if (G_IS_PARAM_SPEC_STRING(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_STRING);
- g_object_get_property (gob, getter->param_name, &gval);
-
- const char * str = g_value_get_string (&gval);
- return (gpointer) str;
- }
- else
- if (G_IS_PARAM_SPEC_INT(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_INT);
- g_object_get_property (gob, getter->param_name, &gval);
-
- int ival = g_value_get_int (&gval);
- return (gpointer) ival;
- }
- else
- if (G_IS_PARAM_SPEC_UINT(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_UINT);
- g_object_get_property (gob, getter->param_name, &gval);
-
- int ival = g_value_get_uint (&gval);
- return (gpointer) ival;
- }
- else
- if (G_IS_PARAM_SPEC_BOOLEAN(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_BOOLEAN);
- g_object_get_property (gob, getter->param_name, &gval);
-
- int ival = g_value_get_boolean (&gval);
- return (gpointer) ival;
- }
-
- PWARN ("unhandled parameter type %s for paramter %s",
- G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
- return NULL;
+ /* Note that the return type must actually be of type
+ * getter->param_type but we just follow the hard-coded
+ * mapping below ... */
+ if (G_IS_PARAM_SPEC_STRING(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_STRING);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ const char * str = g_value_get_string (&gval);
+ return (gpointer) str;
+ }
+ else
+ if (G_IS_PARAM_SPEC_INT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_INT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_int (&gval);
+ return (gpointer) ival;
+ }
+ else
+ if (G_IS_PARAM_SPEC_UINT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_UINT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_uint (&gval);
+ return (gpointer) ival;
+ }
+ else
+ if (G_IS_PARAM_SPEC_BOOLEAN(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_BOOLEAN);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ int ival = g_value_get_boolean (&gval);
+ return (gpointer) ival;
+ }
+
+ PWARN ("unhandled parameter type %s for paramter %s",
+ G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
+ return NULL;
}
static double
qof_gobject_double_getter (gpointer data, QofParam *getter)
{
- GObject *gob = data;
+ GObject *gob = data;
- GParamSpec *gps = getter->param_userdata;
+ GParamSpec *gps = getter->param_userdata;
- /* Note that the return type must actually be of type
- * getter->param_type but we just follow the hard-coded
- * mapping below ... */
- if (G_IS_PARAM_SPEC_FLOAT(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_FLOAT);
- g_object_get_property (gob, getter->param_name, &gval);
-
- double fval = g_value_get_float (&gval);
- return fval;
- }
- else
- if (G_IS_PARAM_SPEC_DOUBLE(gps))
- {
- GValue gval = {G_TYPE_INVALID};
- g_value_init (&gval, G_TYPE_DOUBLE);
- g_object_get_property (gob, getter->param_name, &gval);
-
- double fval = g_value_get_double (&gval);
- return fval;
- }
-
- PWARN ("unhandled parameter type %s for paramter %s",
- G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
- return 0.0;
+ /* Note that the return type must actually be of type
+ * getter->param_type but we just follow the hard-coded
+ * mapping below ... */
+ if (G_IS_PARAM_SPEC_FLOAT(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_FLOAT);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ double fval = g_value_get_float (&gval);
+ return fval;
+ }
+ else
+ if (G_IS_PARAM_SPEC_DOUBLE(gps))
+ {
+ GValue gval = {G_TYPE_INVALID};
+ g_value_init (&gval, G_TYPE_DOUBLE);
+ g_object_get_property (gob, getter->param_name, &gval);
+
+ double fval = g_value_get_double (&gval);
+ return fval;
+ }
+
+ PWARN ("unhandled parameter type %s for paramter %s",
+ G_PARAM_SPEC_TYPE_NAME(gps), getter->param_name);
+ return 0.0;
}
/* =================================================================== */
@@ -191,12 +191,12 @@
static void
qof_gobject_foreach (QofCollection *coll, QofEntityForeachCB cb, gpointer ud)
{
- GSList *n;
- n = qof_collection_get_data (coll);
- for (; n; n=n->next)
- {
- cb (n->data, ud);
- }
+ GSList *n;
+ n = qof_collection_get_data (coll);
+ for (; n; n=n->next)
+ {
+ cb (n->data, ud);
+ }
}
/* =================================================================== */
@@ -205,105 +205,105 @@
qof_gobject_register (QofType e_type, GObjectClass *obclass)
{
- /* Get the GObject properties, convert to QOF properties */
- GParamSpec **prop_list;
- int n_props;
- prop_list = g_object_class_list_properties (obclass, &n_props);
-
- QofParam * qof_param_list = g_new0 (QofParam, n_props);
- paramList = g_slist_prepend (paramList, qof_param_list);
-
- PINFO ("object %s has %d props", e_type, n_props);
- int i, j=0;
- for (i=0; i<n_props; i++)
- {
- GParamSpec *gparam = prop_list[i];
- QofParam *qpar = &qof_param_list[j];
-
- PINFO ("param %d %s is type %s",
- i, gparam->name, G_PARAM_SPEC_TYPE_NAME(gparam));
-
- qpar->param_name = g_param_spec_get_name (gparam);
- qpar->param_getfcn = qof_gobject_getter;
- qpar->param_setfcn = NULL;
- qpar->param_userdata = gparam;
- if ((G_IS_PARAM_SPEC_INT(gparam)) ||
- (G_IS_PARAM_SPEC_UINT(gparam)) ||
- (G_IS_PARAM_SPEC_ENUM(gparam)) ||
- (G_IS_PARAM_SPEC_FLAGS(gparam)))
- {
- qpar->param_type = QOF_TYPE_INT32;
- j++;
- }
- else
- if ((G_IS_PARAM_SPEC_INT64(gparam)) ||
- (G_IS_PARAM_SPEC_UINT64(gparam)))
- {
- qpar->param_type = QOF_TYPE_INT64;
- j++;
- }
- else
- if (G_IS_PARAM_SPEC_BOOLEAN(gparam))
- {
- qpar->param_type = QOF_TYPE_BOOLEAN;
- j++;
- }
- else
- if (G_IS_PARAM_SPEC_STRING(gparam))
- {
- qpar->param_type = QOF_TYPE_STRING;
- j++;
- }
- else
- if ((G_IS_PARAM_SPEC_POINTER(gparam)) ||
- (G_IS_PARAM_SPEC_OBJECT(gparam)))
- {
- /* No-op, silently ignore. Someday we should handle this ... */
- }
- else
- if ((G_IS_PARAM_SPEC_FLOAT(gparam)) ||
- (G_IS_PARAM_SPEC_DOUBLE(gparam)))
- {
- qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter;
- qpar->param_type = QOF_TYPE_DOUBLE;
- j++;
- }
- else
- if (G_IS_PARAM_SPEC_CHAR(gparam))
- {
- qpar->param_type = QOF_TYPE_CHAR;
- j++;
- }
- else
- {
- PWARN ("Unknown/unhandled parameter type %s on %s:%s\n",
- G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name);
- }
- }
+ /* Get the GObject properties, convert to QOF properties */
+ GParamSpec **prop_list;
+ int n_props;
+ prop_list = g_object_class_list_properties (obclass, &n_props);
+
+ QofParam * qof_param_list = g_new0 (QofParam, n_props);
+ paramList = g_slist_prepend (paramList, qof_param_list);
+
+ PINFO ("object %s has %d props", e_type, n_props);
+ int i, j=0;
+ for (i=0; i<n_props; i++)
+ {
+ GParamSpec *gparam = prop_list[i];
+ QofParam *qpar = &qof_param_list[j];
+
+ PINFO ("param %d %s is type %s",
+ i, gparam->name, G_PARAM_SPEC_TYPE_NAME(gparam));
+
+ qpar->param_name = g_param_spec_get_name (gparam);
+ qpar->param_getfcn = qof_gobject_getter;
+ qpar->param_setfcn = NULL;
+ qpar->param_userdata = gparam;
+ if ((G_IS_PARAM_SPEC_INT(gparam)) ||
+ (G_IS_PARAM_SPEC_UINT(gparam)) ||
+ (G_IS_PARAM_SPEC_ENUM(gparam)) ||
+ (G_IS_PARAM_SPEC_FLAGS(gparam)))
+ {
+ qpar->param_type = QOF_TYPE_INT32;
+ j++;
+ }
+ else
+ if ((G_IS_PARAM_SPEC_INT64(gparam)) ||
+ (G_IS_PARAM_SPEC_UINT64(gparam)))
+ {
+ qpar->param_type = QOF_TYPE_INT64;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_BOOLEAN(gparam))
+ {
+ qpar->param_type = QOF_TYPE_BOOLEAN;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_STRING(gparam))
+ {
+ qpar->param_type = QOF_TYPE_STRING;
+ j++;
+ }
+ else
+ if ((G_IS_PARAM_SPEC_POINTER(gparam)) ||
+ (G_IS_PARAM_SPEC_OBJECT(gparam)))
+ {
+ /* No-op, silently ignore. Someday we should handle this ... */
+ }
+ else
+ if ((G_IS_PARAM_SPEC_FLOAT(gparam)) ||
+ (G_IS_PARAM_SPEC_DOUBLE(gparam)))
+ {
+ qpar->param_getfcn = (QofAccessFunc) qof_gobject_double_getter;
+ qpar->param_type = QOF_TYPE_DOUBLE;
+ j++;
+ }
+ else
+ if (G_IS_PARAM_SPEC_CHAR(gparam))
+ {
+ qpar->param_type = QOF_TYPE_CHAR;
+ j++;
+ }
+ else
+ {
+ PWARN ("Unknown/unhandled parameter type %s on %s:%s\n",
+ G_PARAM_SPEC_TYPE_NAME(gparam), e_type, qpar->param_name);
+ }
+ }
- /* NULL-terminated list! */
- qof_param_list[j].param_type = NULL;
+ /* NULL-terminated list! */
+ qof_param_list[j].param_type = NULL;
- qof_class_register (e_type, NULL, qof_param_list);
+ qof_class_register (e_type, NULL, qof_param_list);
- /* ------------------------------------------------------ */
+ /* ------------------------------------------------------ */
/* Now do the class itself */
- QofObject *class_def = g_new0 (QofObject, 1);
- classList = g_slist_prepend (classList, class_def);
+ QofObject *class_def = g_new0 (QofObject, 1);
+ classList = g_slist_prepend (classList, class_def);
- class_def->interface_version = QOF_OBJECT_VERSION;
- class_def->e_type = e_type;
- /* We could let the user specify a "nick" here, but
- * the actual class name seems reasonable, e.g. for debugging. */
- class_def->type_label = G_OBJECT_CLASS_NAME (obclass);
- class_def->book_begin = NULL;
- class_def->book_end = NULL;
- class_def->is_dirty = NULL;
- class_def->mark_clean = NULL;
- class_def->foreach = qof_gobject_foreach;
- class_def->printable = NULL;
+ class_def->interface_version = QOF_OBJECT_VERSION;
+ class_def->e_type = e_type;
+ /* We could let the user specify a "nick" here, but
+ * the actual class name seems reasonable, e.g. for debugging. */
+ class_def->type_label = G_OBJECT_CLASS_NAME (obclass);
+ class_def->book_begin = NULL;
+ class_def->book_end = NULL;
+ class_def->is_dirty = NULL;
+ class_def->mark_clean = NULL;
+ class_def->foreach = qof_gobject_foreach;
+ class_def->printable = NULL;
- qof_object_register (class_def);
+ qof_object_register (class_def);
}
/* ======================= END OF FILE ================================ */
Index: qofclass.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lsrc/engine/qofclass.c -Lsrc/engine/qofclass.c -u -r1.2 -r1.3
--- src/engine/qofclass.c
+++ src/engine/qofclass.c
@@ -51,23 +51,31 @@
QofSortFunc default_sort_function,
const QofParam *params)
{
+ GHashTable *ht;
int i;
if (!obj_name) return;
if (default_sort_function)
+ {
g_hash_table_insert (sortTable, (char *)obj_name, default_sort_function);
+ }
- if (params) {
- GHashTable *ht = g_hash_table_lookup (paramTable, obj_name);
+ ht = g_hash_table_lookup (paramTable, obj_name);
- /* If it doesn't already exist, create a new table for this object */
- if (!ht) {
- ht = g_hash_table_new (g_str_hash, g_str_equal);
- g_hash_table_insert (paramTable, (char *)obj_name, ht);
- }
+ /* If it doesn't already exist, create a new table for this object */
+ if (!ht)
+ {
+ ht = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (paramTable, (char *)obj_name, ht);
+ }
- /* Now insert all the parameters */
+ /* At least right now, we allow dummy, paramterless objects,
+ * for testing purposes. Although I suppose that should be
+ * an error.. */
+ /* Now insert all the parameters */
+ if (params)
+ {
for (i = 0; params[i].param_name; i++)
g_hash_table_insert (ht,
(char *)params[i].param_name,
@@ -96,6 +104,15 @@
g_hash_table_destroy (sortTable);
}
+gboolean
+qof_class_is_registered (QofIdTypeConst obj_name)
+{
+ if (!obj_name) return FALSE;
+
+ if (g_hash_table_lookup (paramTable, obj_name)) return TRUE;
+
+ return FALSE;
+}
const QofParam *
qof_class_get_parameter (QofIdTypeConst obj_name,
Index: kvp_frame.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/kvp_frame.h,v
retrieving revision 1.33
retrieving revision 1.34
diff -Lsrc/engine/kvp_frame.h -Lsrc/engine/kvp_frame.h -u -r1.33 -r1.34
--- src/engine/kvp_frame.h
+++ src/engine/kvp_frame.h
@@ -74,9 +74,16 @@
/** Enum to enumerate possible types in the union KvpValue
* XXX FIXME TODO: People have asked for boolean values,
* e.g. in xaccAccountSetAutoInterestXfer
+ *
+ * XXX In the long run, this should be synchronized with the
+ * core QOF types, which in turn should be synced to the g_types
+ * in GLib. Unfortuantely, this requies writing a pile of code
+ * to handle all of the different cases.
+ * An alternative might be to make kvp values inherit from the
+ * core g_types (i.e. add new core g_types) ??
*/
typedef enum {
- KVP_TYPE_GINT64,
+ KVP_TYPE_GINT64=1,
KVP_TYPE_DOUBLE,
KVP_TYPE_NUMERIC,
KVP_TYPE_STRING,
--- /dev/null
+++ src/engine/qofquery-deserial.h
@@ -0,0 +1,42 @@
+/********************************************************************\
+ * qofquery-deserial.h -- Convert Qof-Query XML to QofQuery *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 *
+ * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
+ * Boston, MA 02111-1307, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+/** @file qofquery-deserial.h
+ @breif Convert Qof-Query XML to QofQuery
+
+ Qof Queries can be convrted to and from XML so that they
+ can be sent from here to there. This file implements the
+ routine needed to convert the XML back into a C struct.
+
+ @author Copyright (C) 2004 Linas Vepstas <linas at linas.org>
+*/
+
+#ifndef QOF_QUERY_DESERIAL_H
+#define QOF_QUERY_DESERIAL_H
+
+#include <qof/qofquery.h>
+#include <libxml/tree.h>
+
+/** Given an XML tree, reconstruct and return the equivalent query. */
+QofQuery *qof_query_from_xml (xmlNodePtr);
+
+#endif /* QOF_QUERY_DESERIAL_H */
--- /dev/null
+++ src/engine/qofquery-serialize.h
@@ -0,0 +1,41 @@
+/********************************************************************\
+ * qofquery-serialize.h -- Convert QofQuery to XML *
+ * Copyright (C) 2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 *
+ * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
+ * Boston, MA 02111-1307, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+/** @file qofquery-serialize.h
+ @breif Convert QofQuery to XML
+ @author Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org>
+ */
+
+#ifndef QOF_QUERY_SERIALIZE_H
+#define QOF_QUERY_SERIALIZE_H
+
+#include <qof/qofquery.h>
+#include <libxml/tree.h>
+
+/** Take the query passed as input, and serialize it into XML.
+ * The DTD used will be a very qofquery specific DTD
+ * This is NOT the XQuery XML.
+ */
+xmlNodePtr qof_query_to_xml (QofQuery *q);
+
+#endif /* QOF_QUERY_SERIALIZE_H */
Index: qofsession.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -Lsrc/engine/qofsession.c -Lsrc/engine/qofsession.c -u -r1.8 -r1.9
--- src/engine/qofsession.c
+++ src/engine/qofsession.c
@@ -1100,6 +1100,7 @@
void
gnc_run_rpc_server (void)
{
+#ifdef GNUCASH
const char * dll_err;
void * dll_handle;
int (*rpc_run)(short);
@@ -1132,6 +1133,7 @@
ret = (*rpc_run)(0);
/* XXX How do we force an exit? */
+#endif /* GNUCASH */
}
/* =================== END OF FILE ====================================== */
--- /dev/null
+++ src/engine/qofquery-serialize.c
@@ -0,0 +1,555 @@
+/********************************************************************\
+ * qofquery-serialize.c -- Convert QofQuery to XML *
+ * Copyright (C) 2001,2002,2004 Linas Vepstas <linas at linas.org> *
+ * *
+ * 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 *
+ * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
+ * Boston, MA 02111-1307, USA gnu at gnu.org *
+ * *
+\********************************************************************/
+
+#include "config.h"
+
+#include "qofquery-serialize.h"
+#include "qofquery-p.h"
+#include "qofquerycore-p.h"
+#include "kvp_frame.h"
+
+/* ======================================================= */
+
+#define PUT_STR(TOK,VAL) { \
+ xmlNodePtr node; \
+ const char * str = (VAL); \
+ if (str && 0 != str[0]) \
+ { \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+ } \
+}
+
+#define PUT_INT32(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%d", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_INT64(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%lld", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_DBL(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ g_snprintf (buff, sizeof(buff), "%.18g", (VAL)); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_GUID(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ guid_to_string_buff ((VAL), buff); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_DATE(TOK,VAL) { \
+ xmlNodePtr node; \
+ char buff[80]; \
+ gnc_timespec_to_iso8601_buff ((VAL), buff); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, buff); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_NUMERIC(TOK,VAL) { \
+ xmlNodePtr node; \
+ char *str; \
+ str = gnc_numeric_to_string (VAL); \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ g_free (str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_BOOL(TOK,VAL) { \
+ xmlNodePtr node; \
+ gboolean boll = (VAL); \
+ node = xmlNewNode (NULL, TOK); \
+ if (boll) { \
+ xmlNodeAddContent(node, "T"); \
+ } else { \
+ xmlNodeAddContent(node, "F"); \
+ } \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_HOW(TOK,VAL,A,B,C,D,E,F) { \
+ xmlNodePtr node; \
+ const char * str = "EQUAL"; \
+ switch (VAL) \
+ { \
+ case QOF_COMPARE_##A: str = #A; break; \
+ case QOF_COMPARE_##B: str = #B; break; \
+ case QOF_COMPARE_##C: str = #C; break; \
+ case QOF_COMPARE_##D: str = #D; break; \
+ case QOF_COMPARE_##E: str = #E; break; \
+ case QOF_COMPARE_##F: str = #F; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH2(TOK,VAL,PFX,A,B) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH3(TOK,VAL,PFX,A,B,C) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ case QOF_##PFX##_##C: str = #C; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+#define PUT_MATCH5(TOK,VAL,PFX,A,B,C,D,E) { \
+ xmlNodePtr node; \
+ const char * str = #A; \
+ switch (VAL) \
+ { \
+ case QOF_##PFX##_##A: str = #A; break; \
+ case QOF_##PFX##_##B: str = #B; break; \
+ case QOF_##PFX##_##C: str = #C; break; \
+ case QOF_##PFX##_##D: str = #D; break; \
+ case QOF_##PFX##_##E: str = #E; break; \
+ } \
+ node = xmlNewNode (NULL, TOK); \
+ xmlNodeAddContent(node, str); \
+ xmlAddChild (topnode, node); \
+}
+
+/* ======================================================= */
+
+static void
+qof_kvp_value_to_xml (KvpValue *kval, xmlNodePtr topnode)
+{
+ KvpValueType kvt = kvp_value_get_type (kval);
+
+ switch (kvt)
+ {
+ case KVP_TYPE_GINT64:
+ PUT_INT64 ("qofquery:int64", kvp_value_get_gint64(kval));
+ break;
+ case KVP_TYPE_DOUBLE:
+ PUT_DBL ("qofquery:double", kvp_value_get_double(kval));
+ break;
+ case KVP_TYPE_NUMERIC:
+ PUT_NUMERIC ("qofquery:numeric", kvp_value_get_numeric(kval));
+ break;
+ case KVP_TYPE_GUID:
+ PUT_GUID ("qofquery:guid", kvp_value_get_guid(kval));
+ break;
+ case KVP_TYPE_STRING:
+ PUT_STR ("qofquery:string", kvp_value_get_string(kval));
+ break;
+ case KVP_TYPE_TIMESPEC:
+ PUT_DATE ("qofquery:date", kvp_value_get_timespec(kval));
+ break;
+ case KVP_TYPE_BINARY:
+ case KVP_TYPE_GLIST:
+ case KVP_TYPE_FRAME:
+ // XXX don't know how to support these.
+ break;
+ }
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_pred_data_to_xml (QofQueryPredData *pd)
+{
+
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-guid");
+ /* GUID Predicate doesn't do a PUT_HOW */
+
+ GList *n;
+ query_guid_t pdata = (query_guid_t) pd;
+ PUT_MATCH5("qofquery:guid-match", pdata->options,
+ GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
+
+ for (n = pdata->guids; n; n = n->next)
+ {
+ PUT_GUID ("qofquery:guid", n->data);
+ }
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-string");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_string_t pdata = (query_string_t) pd;
+ PUT_MATCH2("qofquery:string-match", pdata->options,
+ STRING_MATCH, NORMAL, CASEINSENSITIVE);
+ PUT_BOOL ("qofquery:is-regex", pdata->is_regex);
+ PUT_STR ("qofquery:string", pdata->matchstring);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_numeric_t pdata = (query_numeric_t) pd;
+ PUT_MATCH3("qofquery:numeric-match", pdata->options,
+ NUMERIC_MATCH, DEBIT, CREDIT, ANY);
+
+ PUT_NUMERIC ("qofquery:numeric", pdata->amount);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_kvp_t pdata = (query_kvp_t) pd;
+
+ GSList *n;
+ for (n=pdata->path; n; n=n->next)
+ {
+ PUT_STR ("qofquery:kvp-path", n->data);
+ }
+ qof_kvp_value_to_xml (pdata->value, topnode);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-date");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_date_t pdata = (query_date_t) pd;
+
+ PUT_MATCH2("qofquery:date-match", pdata->options,
+ DATE_MATCH, NORMAL, ROUNDED);
+
+ PUT_DATE ("qofquery:date", pdata->date);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-int64");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_int64_t pdata = (query_int64_t) pd;
+ PUT_INT64 ("qofquery:int64", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-int32");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_int32_t pdata = (query_int32_t) pd;
+
+ PUT_INT32 ("qofquery:int32", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-double");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_double_t pdata = (query_double_t) pd;
+
+ PUT_DBL ("qofquery:double", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
+ PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
+
+ query_boolean_t pdata = (query_boolean_t) pd;
+
+ PUT_BOOL ("qofquery:boolean", pdata->val);
+ return topnode;
+ }
+ if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
+ {
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:pred-char");
+ /* There is no PUT_HOW for char-match */
+ query_char_t pdata = (query_char_t) pd;
+
+ PUT_MATCH2("qofquery:char-match", pdata->options,
+ CHAR_MATCH, ANY, NONE);
+
+ PUT_STR ("qofquery:char-list", pdata->char_list);
+ return topnode;
+ }
+ return NULL;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_param_path_to_xml (GSList *param_path)
+{
+ xmlNodePtr topnode = xmlNewNode (NULL, "qofquery:param-path");
+ GSList *n = param_path;
+ for ( ; n; n=n->next)
+ {
+ QofIdTypeConst path = n->data;
+ if (!path) continue;
+ PUT_STR ("qofquery:param", path);
+ }
+ return topnode;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_one_term_to_xml (QofQueryTerm *qt)
+{
+ xmlNodePtr node;
+ xmlNodePtr term = xmlNewNode (NULL, "qofquery:term");
+
+ gboolean invert = qof_query_term_is_inverted (qt);
+ GSList *path = qof_query_term_get_param_path (qt);
+ QofQueryPredData *pd = qof_query_term_get_pred_data (qt);
+
+ xmlNodePtr topnode = term;
+ if (invert)
+ {
+ /* inverter becomes new top mode */
+ topnode = xmlNewNode (NULL, "qofquery:invert");
+ xmlAddChild (term, topnode);
+ }
+
+ node = qof_query_param_path_to_xml (path);
+ if (node) xmlAddChild (topnode, node);
+
+ node = qof_query_pred_data_to_xml (pd);
+ if (node) xmlAddChild (topnode, node);
+
+ return term;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_and_terms_to_xml (GList *and_terms)
+{
+ xmlNodePtr terms = xmlNewNode (NULL, "qofquery:and-terms");
+ GList *n = and_terms;
+ for ( ; n; n=n->next)
+ {
+ QofQueryTerm *qt = n->data;
+ if (!qt) continue;
+
+ xmlNodePtr t = qof_query_one_term_to_xml (n->data);
+ if (t) xmlAddChild (terms, t);
+ }
+ return terms;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_terms_to_xml (QofQuery *q)
+{
+ xmlNodePtr terms = NULL;
+ GList *n = qof_query_get_terms (q);
+
+ if (!n) return NULL;
+ terms = xmlNewNode (NULL, "qofquery:or-terms");
+
+ for ( ; n; n=n->next)
+ {
+ xmlNodePtr andt = qof_query_and_terms_to_xml (n->data);
+ if (andt) xmlAddChild (terms, andt);
+ }
+ return terms;
+}
+
+/* ======================================================= */
+
+static xmlNodePtr
+qof_query_sorts_to_xml (QofQuery *q)
+{
+ QofQuerySort *s[3];
+ qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
+
+ if (NULL == s[0]) return NULL;
+
+ xmlNodePtr sortlist = xmlNewNode (NULL, "qofquery:sort-list");
+ int i;
+ for (i=0; i<3; i++)
+ {
+ if (NULL == s[i]) continue;
+
+ GSList *plist = qof_query_sort_get_param_path (s[i]);
+ if (!plist) continue;
+
+ xmlNodePtr sort = xmlNewNode (NULL, "qofquery:sort");
+ xmlAddChild (sortlist, sort);
+
+ xmlNodePtr topnode = sort;
+
+ gboolean increasing = qof_query_sort_get_increasing (s[i]);
+ PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
+
+ gint opt = qof_query_sort_get_sort_options (s[i]);
+ PUT_INT32 ("qofquery:options", opt);
+
+ xmlNodePtr pl = qof_query_param_path_to_xml (plist);
+ if (pl) xmlAddChild (sort, pl);
+ }
+
+ return sortlist;
+}
+
+/* ======================================================= */
+
+static void
+do_qof_query_to_xml (QofQuery *q, xmlNodePtr topnode)
+{
+ QofIdType search_for = qof_query_get_search_for (q);
+ PUT_STR ("qofquery:search-for", search_for);
+
+ xmlNodePtr terms = qof_query_terms_to_xml(q);
+ if (terms) xmlAddChild (topnode, terms);
+
+ xmlNodePtr sorts = qof_query_sorts_to_xml (q);
+ if (sorts) xmlAddChild (topnode, sorts);
+
+ gint max_results = qof_query_get_max_results (q);
+ PUT_INT32 ("qofquery:max-results", max_results);
+}
+
+/* ======================================================= */
+
+xmlNodePtr
+qof_query_to_xml (QofQuery *q)
+{
+ xmlNodePtr topnode;
+ xmlNodePtr node;
+ xmlNsPtr ns;
+
+ topnode = xmlNewNode(NULL, "qof:qofquery");
+ xmlSetProp(topnode, "version", "1.0.1");
+
+ // XXX path to DTD is wrong
+ // ns = xmlNewNs (topnode, "file:" "/usr/share/lib" "/qofquery.dtd", "qof");
+
+ do_qof_query_to_xml (q, topnode);
+
+ return topnode;
+}
+
+/* =============================================================== */
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <qof/qofsql.h>
+
+int main (int argc, char * argv[])
+{
+ QofQuery *q;
+ QofSqlQuery *sq;
+
+ qof_query_init();
+ qof_object_initialize ();
+
+ static QofParam params[] = {
+ { "adate", QOF_TYPE_DATE, NULL, NULL},
+ { "aint", QOF_TYPE_INT32, NULL, NULL},
+ { "aint64", QOF_TYPE_INT64, NULL, NULL},
+ { "astr", QOF_TYPE_STRING, NULL, NULL},
+ { NULL },
+ };
+
+ qof_class_register ("GncABC", NULL, params);
+ sq = qof_sql_query_new();
+
+ qof_sql_query_parse (sq,
+ "SELECT * from GncABC WHERE aint = 123 "
+ "or not astr=\'asdf\' "
+ "and aint64 = 9876123456789;");
+ // qof_sql_query_parse (sq, "SELECT * from GncABC;");
+ q = qof_sql_query_get_query (sq);
+
+ qof_query_print (q);
+
+ xmlDocPtr doc = doc = xmlNewDoc("1.0");
+ xmlNodePtr topnode = qof_query_to_xml (q);
+ xmlDocSetRootElement(doc,topnode);
+
+ xmlChar *xbuf;
+ int bufsz;
+ xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
+
+ printf ("%s\n", xbuf);
+ xmlFree (xbuf);
+ xmlFreeDoc(doc);
+
+#if 0
+printf ("duude\n");
+ // xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
+ xmlOutputBufferPtr xbuf = xmlOutputBufferCreateFile (stdout, NULL);
+printf ("duude\n");
+
+ xbuf = xmlOutputBufferCreateFd (1, NULL);
+printf ("duude\n");
+ xmlNodeDumpOutput (xbuf, NULL, topnode, 99, 99, "iso-8859-1");
+ // xmlElemDump (stdout, NULL, topnode);
+#endif
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
+
+/* ======================== END OF FILE =================== */
Index: guid.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/guid.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -Lsrc/engine/guid.h -Lsrc/engine/guid.h -u -r1.19 -r1.20
--- src/engine/guid.h
+++ src/engine/guid.h
@@ -134,6 +134,9 @@
* 'a' through 'f'. The encoding will always be GUID_ENCODING_LENGTH
* characters long.
*
+ * XXX This routine is not thread safe and is deprecated. Please
+ * use the routine guid_to_string_buff() instead.
+ *
* @param guid The guid to print.
*
* @return A pointer to the starting character of the string. The
Index: qofclass.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -Lsrc/engine/qofclass.h -Lsrc/engine/qofclass.h -u -r1.4 -r1.5
--- src/engine/qofclass.h
+++ src/engine/qofclass.h
@@ -145,6 +145,11 @@
* qof_class_register ("myObjectName", myObjectCompare, &myParams);
*/
+/** Return true if the the indicated type is registered,
+ * else return FALSE.
+ */
+gboolean qof_class_is_registered (QofIdTypeConst obj_name);
+
/** Return the core datatype of the specified object's parameter */
QofType qof_class_get_parameter_type (QofIdTypeConst obj_name,
const char *param_name);
More information about the Gnucash-changes
mailing list