mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Remove completely unused and code from libqof which also doesn't get compiled for years by now.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20508 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
683b7a6bbb
commit
aaa2410309
@ -71,7 +71,6 @@ SET (libgnc_qof_HEADERS
|
||||
qof/qofquerycore.h
|
||||
qof/qofreference.h
|
||||
qof/qofsession.h
|
||||
qof/qofsql.h
|
||||
qof/qofutil.h
|
||||
qof/qofbookmerge.h
|
||||
qof/qof-gobject.h
|
||||
|
@ -65,7 +65,6 @@ qofinclude_HEADERS = \
|
||||
qofquerycore.h \
|
||||
qofreference.h \
|
||||
qofsession.h \
|
||||
qofsql.h \
|
||||
qofutil.h \
|
||||
qofbookmerge.h \
|
||||
qof-gobject.h
|
||||
@ -75,8 +74,6 @@ noinst_HEADERS = \
|
||||
qofclass-p.h \
|
||||
qofmath128.h \
|
||||
qofquery-p.h \
|
||||
qofquery-deserial.h \
|
||||
qofquery-serialize.h \
|
||||
qofbook-p.h \
|
||||
qofevent-p.h \
|
||||
qofobject-p.h \
|
||||
|
@ -92,7 +92,6 @@
|
||||
#include "qofquery.h"
|
||||
#include "qofquerycore.h"
|
||||
#include "qofsession.h"
|
||||
#include "qofsql.h"
|
||||
#include "qofchoice.h"
|
||||
#include "qofbookmerge.h"
|
||||
#include "qofreference.h"
|
||||
|
@ -1,762 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofquery-deserial.c -- Convert Qof-Query XML to QofQuery *
|
||||
* Copyright (C) 2001,2002,2004 Linas Vepstas <linas@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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer built into the QOF library. It remains in CVS until libqof2.*/
|
||||
|
||||
#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 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); \
|
||||
GncGUID 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) \
|
||||
{ \
|
||||
QofQueryPredData *pred; \
|
||||
xmlNodePtr xp; \
|
||||
xmlNodePtr node; \
|
||||
QofQueryCompare how; \
|
||||
CTYPE val; \
|
||||
xp = root->xmlChildrenNode; \
|
||||
\
|
||||
how = QOF_COMPARE_EQUAL; \
|
||||
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); \
|
||||
{} \
|
||||
} \
|
||||
\
|
||||
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 GncGUID * 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)
|
||||
{
|
||||
QofQueryCompare how;
|
||||
GSList *path;
|
||||
KvpValue *value;
|
||||
QofQueryPredData *pred;
|
||||
xmlNodePtr xp;
|
||||
xmlNodePtr node;
|
||||
|
||||
how = QOF_COMPARE_EQUAL;
|
||||
xp = root->xmlChildrenNode;
|
||||
path = NULL;
|
||||
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");
|
||||
}
|
||||
|
||||
pred = qof_query_kvp_predicate (how, path, value);
|
||||
g_slist_free (path);
|
||||
return pred;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
static QofQueryPredData *
|
||||
qof_query_pred_guid_from_xml (xmlNodePtr root)
|
||||
{
|
||||
GList *guid_list, *n;
|
||||
const char *str;
|
||||
GncGUID *guid;
|
||||
gboolean decode;
|
||||
QofQueryPredData *pred;
|
||||
QofGuidMatch sm;
|
||||
xmlNodePtr xp;
|
||||
xmlNodePtr node;
|
||||
guid_list = NULL;
|
||||
|
||||
sm = QOF_GUID_MATCH_ANY;
|
||||
xp = root->xmlChildrenNode;
|
||||
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))
|
||||
{
|
||||
str = GET_TEXT (node);
|
||||
guid = guid_malloc ();
|
||||
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!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pred = qof_query_guid_predicate (sm, guid_list);
|
||||
|
||||
/* The predicate made a copy of everything, so free our stuff */
|
||||
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)
|
||||
{
|
||||
QofQueryPredData *pred;
|
||||
QofCharMatch sm;
|
||||
const char * char_list;
|
||||
xmlNodePtr xp;
|
||||
xmlNodePtr node;
|
||||
|
||||
char_list = NULL;
|
||||
xp = root->xmlChildrenNode;
|
||||
sm = QOF_CHAR_MATCH_ANY;
|
||||
|
||||
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");
|
||||
{}
|
||||
}
|
||||
|
||||
pred = qof_query_char_predicate (sm, char_list);
|
||||
return pred;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
static QofQueryPredData *
|
||||
qof_query_pred_numeric_from_xml (xmlNodePtr root)
|
||||
{
|
||||
QofQueryPredData *pred;
|
||||
xmlNodePtr node;
|
||||
QofQueryCompare how;
|
||||
QofNumericMatch sm;
|
||||
gnc_numeric num;
|
||||
xmlNodePtr xp;
|
||||
|
||||
xp = root->xmlChildrenNode;
|
||||
how = QOF_COMPARE_EQUAL;
|
||||
sm = QOF_NUMERIC_MATCH_ANY;
|
||||
|
||||
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");
|
||||
{}
|
||||
}
|
||||
|
||||
pred = qof_query_numeric_predicate (how, sm, num);
|
||||
return pred;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
static QofQueryPredData *
|
||||
qof_query_pred_date_from_xml (xmlNodePtr root)
|
||||
{
|
||||
xmlNodePtr xp;
|
||||
xmlNodePtr node;
|
||||
QofQueryCompare how;
|
||||
QofDateMatch sm;
|
||||
Timespec date;
|
||||
QofQueryPredData *pred;
|
||||
|
||||
xp = root->xmlChildrenNode;
|
||||
|
||||
how = QOF_COMPARE_EQUAL;
|
||||
sm = QOF_DATE_MATCH_DAY;
|
||||
date = (Timespec)
|
||||
{
|
||||
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, DAY);
|
||||
GET_DATE (0, date = , "qofquery:date");
|
||||
{}
|
||||
}
|
||||
|
||||
pred = qof_query_date_predicate (how, sm, date);
|
||||
return pred;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
static QofQueryPredData *
|
||||
qof_query_pred_string_from_xml (xmlNodePtr root)
|
||||
{
|
||||
QofQueryPredData *pred;
|
||||
xmlNodePtr xp;
|
||||
xmlNodePtr node;
|
||||
QofQueryCompare how;
|
||||
QofStringMatch sm;
|
||||
gboolean is_regex;
|
||||
const char *pstr;
|
||||
|
||||
xp = root->xmlChildrenNode;
|
||||
how = QOF_COMPARE_EQUAL;
|
||||
sm = QOF_STRING_MATCH_CASEINSENSITIVE;
|
||||
is_regex = FALSE;
|
||||
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);
|
||||
{}
|
||||
}
|
||||
pred = qof_query_string_predicate (how, pstr, sm , is_regex);
|
||||
return pred;
|
||||
}
|
||||
|
||||
/* =============================================================== */
|
||||
|
||||
static GSList *
|
||||
qof_query_param_path_from_xml (xmlNodePtr root)
|
||||
{
|
||||
xmlNodePtr pterms;
|
||||
GSList *plist;
|
||||
xmlNodePtr node;
|
||||
|
||||
pterms = root->xmlChildrenNode;
|
||||
plist = NULL;
|
||||
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;
|
||||
QofQueryPredData *pred;
|
||||
GSList *path;
|
||||
QofQuery *qt;
|
||||
QofQuery *qinv;
|
||||
|
||||
pred = NULL;
|
||||
path = NULL;
|
||||
term = root->xmlChildrenNode;
|
||||
for (node = term; node; node = node->next)
|
||||
{
|
||||
if (node->type != XML_ELEMENT_NODE) continue;
|
||||
if (0 == strcmp (node->name, "qofquery:invert"))
|
||||
{
|
||||
qt = qof_query_create();
|
||||
qof_query_term_from_xml (qt, node);
|
||||
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;
|
||||
xmlNodePtr node;
|
||||
|
||||
andterms = root->xmlChildrenNode;
|
||||
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;
|
||||
xmlNodePtr node;
|
||||
QofQuery *qand;
|
||||
|
||||
andterms = root->xmlChildrenNode;
|
||||
for (node = andterms; node; node = node->next)
|
||||
{
|
||||
if (node->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (0 == strcmp (node->name, "qofquery:and-terms"))
|
||||
{
|
||||
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;
|
||||
xmlChar *version;
|
||||
xmlNodePtr qpart;
|
||||
xmlNodePtr node;
|
||||
|
||||
if (!root) return NULL;
|
||||
|
||||
version = xmlGetProp(root, "version");
|
||||
if (!root->name || strcmp ("qof:qofquery", root->name))
|
||||
{
|
||||
// XXX something is wrong. warn ...
|
||||
return NULL;
|
||||
}
|
||||
|
||||
q = qof_query_create ();
|
||||
|
||||
qpart = root->xmlChildrenNode;
|
||||
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;
|
||||
xmlNodePtr topnode;
|
||||
|
||||
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 =================== */
|
@ -1,50 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofquery-deserial.h -- Convert Qof-Query XML to QofQuery *
|
||||
* Copyright (C) 2004 Linas Vepstas <linas@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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
/*
|
||||
qofquery-deserial.h
|
||||
Convert Qof-Query XML to QofQuery
|
||||
author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
#ifndef QOF_QUERY_DESERIAL_H
|
||||
#define QOF_QUERY_DESERIAL_H
|
||||
|
||||
#include "qofquery.h"
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/*
|
||||
Qof Queries can be converted 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.
|
||||
|
||||
Unfinished. XXX Why is this easier than reading a text/sql
|
||||
file?
|
||||
|
||||
NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.
|
||||
|
||||
*/
|
||||
/* Given an XML tree, reconstruct and return the equivalent query. */
|
||||
QofQuery *qof_query_from_xml (xmlNodePtr);
|
||||
|
||||
#endif /* QOF_QUERY_DESERIAL_H */
|
@ -1,601 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofquery-serialize.c -- Convert QofQuery to XML *
|
||||
* Copyright (C) 2001,2002,2004 Linas Vepstas <linas@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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "qofquery-serialize.h"
|
||||
#include "qofquery-p.h"
|
||||
#include "qofquerycore-p.h"
|
||||
#include "kvp_frame.h"
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.*/
|
||||
|
||||
/* ======================================================= */
|
||||
|
||||
#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), "%" G_GINT64_FORMAT, (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)
|
||||
{
|
||||
GList *n;
|
||||
GSList *ns;
|
||||
xmlNodePtr topnode;
|
||||
query_guid_t pdata_g;
|
||||
query_string_t pdata_s;
|
||||
query_numeric_t pdata_n;
|
||||
query_kvp_t pdata_k;
|
||||
query_date_t pdata_d;
|
||||
query_int64_t pdata_i64;
|
||||
query_int32_t pdata_i32;
|
||||
query_double_t pdata_db;
|
||||
query_boolean_t pdata_bool;
|
||||
query_char_t pdata_c;
|
||||
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-guid");
|
||||
/* GncGUID Predicate doesn't do a PUT_HOW */
|
||||
|
||||
pdata_g = (query_guid_t) pd;
|
||||
PUT_MATCH5("qofquery:guid-match", pdata_g->options,
|
||||
GUID_MATCH, ANY, ALL, NONE, NULL, LIST_ANY);
|
||||
|
||||
for (n = pdata_g->guids; n; n = n->next)
|
||||
{
|
||||
PUT_GUID ("qofquery:guid", n->data);
|
||||
}
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-string");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_s = (query_string_t) pd;
|
||||
PUT_MATCH2("qofquery:string-match", pdata_s->options,
|
||||
STRING_MATCH, NORMAL, CASEINSENSITIVE);
|
||||
PUT_BOOL ("qofquery:is-regex", pdata_s->is_regex);
|
||||
PUT_STR ("qofquery:string", pdata_s->matchstring);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-numeric");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_n = (query_numeric_t) pd;
|
||||
PUT_MATCH3("qofquery:numeric-match", pdata_n->options,
|
||||
NUMERIC_MATCH, DEBIT, CREDIT, ANY);
|
||||
|
||||
PUT_NUMERIC ("qofquery:numeric", pdata_n->amount);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-kvp");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_k = (query_kvp_t) pd;
|
||||
for (ns = pdata_k->path; ns; ns = ns->next)
|
||||
{
|
||||
PUT_STR ("qofquery:kvp-path", ns->data);
|
||||
}
|
||||
qof_kvp_value_to_xml (pdata_k->value, topnode);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-date");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_d = (query_date_t) pd;
|
||||
|
||||
PUT_MATCH2("qofquery:date-match", pdata_d->options,
|
||||
DATE_MATCH, NORMAL, DAY);
|
||||
|
||||
PUT_DATE ("qofquery:date", pdata_d->date);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-int64");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_i64 = (query_int64_t) pd;
|
||||
PUT_INT64 ("qofquery:int64", pdata_i64->val);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-int32");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_i32 = (query_int32_t) pd;
|
||||
|
||||
PUT_INT32 ("qofquery:int32", pdata_i32->val);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-double");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_db = (query_double_t) pd;
|
||||
|
||||
PUT_DBL ("qofquery:double", pdata_db->val);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-boolean");
|
||||
PUT_HOW ("qofquery:compare", pd->how, LT, LTE, EQUAL, GT, GTE, NEQ);
|
||||
|
||||
pdata_bool = (query_boolean_t) pd;
|
||||
|
||||
PUT_BOOL ("qofquery:boolean", pdata_bool->val);
|
||||
return topnode;
|
||||
}
|
||||
if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
|
||||
{
|
||||
topnode = xmlNewNode (NULL, "qofquery:pred-char");
|
||||
/* There is no PUT_HOW for char-match */
|
||||
pdata_c = (query_char_t) pd;
|
||||
|
||||
PUT_MATCH2("qofquery:char-match", pdata_c->options,
|
||||
CHAR_MATCH, ANY, NONE);
|
||||
|
||||
PUT_STR ("qofquery:char-list", pdata_c->char_list);
|
||||
return topnode;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ======================================================= */
|
||||
|
||||
static xmlNodePtr
|
||||
qof_query_param_path_to_xml (GSList *param_path)
|
||||
{
|
||||
xmlNodePtr topnode;
|
||||
GSList *n;
|
||||
QofIdTypeConst path;
|
||||
|
||||
n = param_path;
|
||||
topnode = xmlNewNode (NULL, "qofquery:param-path");
|
||||
for ( ; n; n = n->next)
|
||||
{
|
||||
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;
|
||||
xmlNodePtr topnode;
|
||||
gboolean invert;
|
||||
GSList *path;
|
||||
QofQueryPredData *pd;
|
||||
|
||||
invert = qof_query_term_is_inverted (qt);
|
||||
term = xmlNewNode (NULL, "qofquery:term");
|
||||
topnode = term;
|
||||
path = qof_query_term_get_param_path (qt);
|
||||
pd = qof_query_term_get_pred_data (qt);
|
||||
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;
|
||||
GList *n;
|
||||
QofQueryTerm *qt;
|
||||
xmlNodePtr t;
|
||||
|
||||
terms = xmlNewNode (NULL, "qofquery:and-terms");
|
||||
n = and_terms;
|
||||
for ( ; n; n = n->next)
|
||||
{
|
||||
qt = n->data;
|
||||
if (!qt) continue;
|
||||
|
||||
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;
|
||||
GList *n;
|
||||
xmlNodePtr andt;
|
||||
|
||||
terms = NULL;
|
||||
n = qof_query_get_terms (q);
|
||||
if (!n) return NULL;
|
||||
terms = xmlNewNode (NULL, "qofquery:or-terms");
|
||||
|
||||
for ( ; n; n = n->next)
|
||||
{
|
||||
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];
|
||||
xmlNodePtr sortlist;
|
||||
GSList *plist;
|
||||
xmlNodePtr sort;
|
||||
xmlNodePtr topnode;
|
||||
gboolean increasing;
|
||||
gint opt;
|
||||
xmlNodePtr pl;
|
||||
int i;
|
||||
|
||||
qof_query_get_sorts (q, &s[0], &s[1], &s[2]);
|
||||
|
||||
if (NULL == s[0]) return NULL;
|
||||
|
||||
sortlist = xmlNewNode (NULL, "qofquery:sort-list");
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (NULL == s[i]) continue;
|
||||
|
||||
plist = qof_query_sort_get_param_path (s[i]);
|
||||
if (!plist) continue;
|
||||
|
||||
sort = xmlNewNode (NULL, "qofquery:sort");
|
||||
xmlAddChild (sortlist, sort);
|
||||
|
||||
topnode = sort;
|
||||
|
||||
increasing = qof_query_sort_get_increasing (s[i]);
|
||||
PUT_STR ("qofquery:order", increasing ? "DESCENDING" : "ASCENDING");
|
||||
|
||||
opt = qof_query_sort_get_sort_options (s[i]);
|
||||
PUT_INT32 ("qofquery:options", opt);
|
||||
|
||||
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;
|
||||
xmlNodePtr terms;
|
||||
xmlNodePtr sorts;
|
||||
gint max_results;
|
||||
|
||||
search_for = qof_query_get_search_for (q);
|
||||
PUT_STR ("qofquery:search-for", search_for);
|
||||
|
||||
terms = qof_query_terms_to_xml(q);
|
||||
if (terms) xmlAddChild (topnode, terms);
|
||||
|
||||
sorts = qof_query_sorts_to_xml (q);
|
||||
if (sorts) xmlAddChild (topnode, sorts);
|
||||
|
||||
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;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr topnode;
|
||||
xmlChar *xbuf;
|
||||
int bufsz;
|
||||
xmlOutputBufferPtr xbuf;
|
||||
|
||||
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);
|
||||
|
||||
doc = doc = xmlNewDoc("1.0");
|
||||
topnode = qof_query_to_xml (q);
|
||||
xmlDocSetRootElement(doc, topnode);
|
||||
|
||||
xmlDocDumpFormatMemory (doc, &xbuf, &bufsz, 1);
|
||||
|
||||
printf ("%s\n", xbuf);
|
||||
xmlFree (xbuf);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
#if 0
|
||||
printf ("duude\n");
|
||||
// xmlOutputBufferPtr xbuf = xmlAllocOutputBuffer (enc);
|
||||
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 =================== */
|
@ -1,45 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofquery-serialize.h -- Convert QofQuery to XML *
|
||||
* Copyright (C) 2004 Linas Vepstas <linas@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 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
* *
|
||||
\********************************************************************/
|
||||
/* qofquery-serialize.h
|
||||
Convert QofQuery to XML
|
||||
Copyright (C) 2001,2002,2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
/* NOTE: Development of this idea has ceased and this file is
|
||||
no longer included in the QOF library. It remains in CVS for now.*/
|
||||
|
||||
#ifndef QOF_QUERY_SERIALIZE_H
|
||||
#define QOF_QUERY_SERIALIZE_H
|
||||
|
||||
#include "qofquery.h"
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/* XML Serialize Queries to/from XML */
|
||||
|
||||
/* 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 */
|
@ -1,999 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofsql.c -- QOF client-side SQL parser *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/**
|
||||
@file qofsql.c
|
||||
@brief QOF client-side SQL parser - interfaces with libgda.
|
||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h> /* for working atoll */
|
||||
#include <errno.h>
|
||||
#include "glib.h"
|
||||
#ifdef HAVE_GDA
|
||||
#include <sql/sql_parser.h>
|
||||
#else
|
||||
#include "sql_parser.h"
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "qof.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QUERY;
|
||||
|
||||
/* =================================================================== */
|
||||
|
||||
struct _QofSqlQuery
|
||||
{
|
||||
sql_statement *parse_result;
|
||||
QofQuery *qof_query;
|
||||
QofBook *book;
|
||||
char * single_global_tablename;
|
||||
KvpFrame *kvp_join;
|
||||
GList *param_list;
|
||||
QofInstance *inserted_entity;
|
||||
};
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
QofSqlQuery *
|
||||
qof_sql_query_new(void)
|
||||
{
|
||||
QofSqlQuery * sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
|
||||
|
||||
sqn->qof_query = NULL;
|
||||
sqn->parse_result = NULL;
|
||||
sqn->book = NULL;
|
||||
sqn->single_global_tablename = NULL;
|
||||
sqn->kvp_join = NULL;
|
||||
|
||||
return sqn;
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
void
|
||||
qof_sql_query_destroy (QofSqlQuery *q)
|
||||
{
|
||||
if (!q) return;
|
||||
qof_query_destroy (q->qof_query);
|
||||
sql_destroy (q->parse_result);
|
||||
g_free (q);
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
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)
|
||||
{
|
||||
if (!q) return;
|
||||
q->book = book;
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
void
|
||||
qof_sql_query_set_kvp (QofSqlQuery *q, KvpFrame *kvp)
|
||||
{
|
||||
if (!q) return;
|
||||
q->kvp_join = kvp;
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
static inline void
|
||||
get_table_and_param (char * str, char **tab, char **param)
|
||||
{
|
||||
char * end = strchr (str, '.');
|
||||
if (!end)
|
||||
{
|
||||
*tab = 0;
|
||||
*param = str;
|
||||
return;
|
||||
}
|
||||
*end = 0;
|
||||
*tab = str;
|
||||
*param = end + 1;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
dequote_string (char *str)
|
||||
{
|
||||
size_t len;
|
||||
/* strip out quotation marks ... */
|
||||
if (('\'' == str[0]) ||
|
||||
('\"' == str[0]))
|
||||
{
|
||||
str ++;
|
||||
len = strlen(str);
|
||||
str[len-1] = 0;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static QofQuery *
|
||||
handle_single_condition (QofSqlQuery *query, sql_condition * cond)
|
||||
{
|
||||
char tmpbuff[128];
|
||||
GSList *param_list;
|
||||
GList *guid_list;
|
||||
QofQueryPredData *pred_data;
|
||||
sql_field_item *sparam, *svalue;
|
||||
char * qparam_name, *qvalue_name, *table_name, *param_name;
|
||||
char *sep, *path, *str, *p;
|
||||
QofQuery *qq;
|
||||
KvpValue *kv, *kval;
|
||||
KvpValueType kvt;
|
||||
QofQueryCompare qop;
|
||||
time_t exact;
|
||||
int rc, len;
|
||||
Timespec ts;
|
||||
QofType param_type;
|
||||
QofGuidMatch gm;
|
||||
|
||||
pred_data = NULL;
|
||||
if (NULL == cond)
|
||||
{
|
||||
PWARN("missing condition");
|
||||
return NULL;
|
||||
}
|
||||
/* -------------------------------- */
|
||||
/* field to match, assumed, for now to be on the left */
|
||||
/* XXX fix this so it can be either left or right */
|
||||
if (NULL == cond->d.pair.left)
|
||||
{
|
||||
PWARN("missing left parameter");
|
||||
return NULL;
|
||||
}
|
||||
sparam = cond->d.pair.left->item;
|
||||
if (SQL_name != sparam->type)
|
||||
{
|
||||
PWARN("we support only parameter names at this time (parsed %d)",
|
||||
sparam->type);
|
||||
return NULL;
|
||||
}
|
||||
qparam_name = sparam->d.name->data;
|
||||
if (NULL == qparam_name)
|
||||
{
|
||||
PWARN ("missing parameter name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* -------------------------------- */
|
||||
/* value to match, assumed, for now, to be on the right. */
|
||||
/* XXX fix this so it can be either left or right */
|
||||
if (NULL == cond->d.pair.right)
|
||||
{
|
||||
PWARN ("missing right parameter");
|
||||
return NULL;
|
||||
}
|
||||
svalue = cond->d.pair.right->item;
|
||||
if (SQL_name != svalue->type)
|
||||
{
|
||||
PWARN("we support only simple values (parsed as %d)", svalue->type);
|
||||
return NULL;
|
||||
}
|
||||
qvalue_name = svalue->d.name->data;
|
||||
if (NULL == qvalue_name)
|
||||
{
|
||||
PWARN("missing value");
|
||||
return NULL;
|
||||
}
|
||||
qvalue_name = dequote_string (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. */
|
||||
if (0 == g_ascii_strncasecmp (qvalue_name, "kvp://", 6))
|
||||
{
|
||||
if (NULL == query->kvp_join)
|
||||
{
|
||||
PWARN ("missing kvp frame");
|
||||
return NULL;
|
||||
}
|
||||
kv = kvp_frame_get_value (query->kvp_join, qvalue_name + 5);
|
||||
/* If there's no value, its not an error;
|
||||
* we just don't do this predicate */
|
||||
if (!kv) return NULL;
|
||||
kvt = kvp_value_get_type (kv);
|
||||
|
||||
tmpbuff[0] = 0x0;
|
||||
qvalue_name = tmpbuff;
|
||||
switch (kvt)
|
||||
{
|
||||
case KVP_TYPE_GINT64:
|
||||
{
|
||||
gint64 ival = kvp_value_get_gint64(kv);
|
||||
sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_DOUBLE:
|
||||
{
|
||||
double ival = kvp_value_get_double(kv);
|
||||
sprintf (tmpbuff, "%26.18g\n", ival);
|
||||
break;
|
||||
}
|
||||
case KVP_TYPE_STRING:
|
||||
/* If there's no value, its not an error;
|
||||
* we just don't do this predicate */
|
||||
qvalue_name = kvp_value_get_string (kv);
|
||||
if (!qvalue_name) return NULL;
|
||||
break;
|
||||
case KVP_TYPE_GUID:
|
||||
case KVP_TYPE_TIMESPEC:
|
||||
case KVP_TYPE_BINARY:
|
||||
case KVP_TYPE_GLIST:
|
||||
case KVP_TYPE_NUMERIC:
|
||||
case KVP_TYPE_FRAME:
|
||||
PWARN ("unhandled kvp type=%d", kvt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------- */
|
||||
/* Now start building the QOF parameter */
|
||||
param_list = qof_query_build_param_list (qparam_name, NULL);
|
||||
|
||||
/* Get the where-term comparison operator */
|
||||
switch (cond->op)
|
||||
{
|
||||
case SQL_eq:
|
||||
qop = QOF_COMPARE_EQUAL;
|
||||
break;
|
||||
case SQL_gt:
|
||||
qop = QOF_COMPARE_GT;
|
||||
break;
|
||||
case SQL_lt:
|
||||
qop = QOF_COMPARE_LT;
|
||||
break;
|
||||
case SQL_geq:
|
||||
qop = QOF_COMPARE_GTE;
|
||||
break;
|
||||
case SQL_leq:
|
||||
qop = QOF_COMPARE_LTE;
|
||||
break;
|
||||
case SQL_diff:
|
||||
qop = QOF_COMPARE_NEQ;
|
||||
break;
|
||||
default:
|
||||
/* XXX for string-type queries, we should be able to
|
||||
* support 'IN' for substring search. Also regex. */
|
||||
PWARN ("Unsupported compare op (parsed as %u)", cond->op);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* OK, need to know the type of the thing being matched
|
||||
* in order to build the correct predicate. Get the type
|
||||
* from the object parameters. */
|
||||
get_table_and_param (qparam_name, &table_name, ¶m_name);
|
||||
if (NULL == table_name)
|
||||
{
|
||||
table_name = query->single_global_tablename;
|
||||
}
|
||||
if (NULL == table_name)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
param_type = qof_class_get_parameter_type (table_name, param_name);
|
||||
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))
|
||||
{
|
||||
pred_data =
|
||||
qof_query_string_predicate (qop, /* comparison to make */
|
||||
qvalue_name, /* string to match */
|
||||
QOF_STRING_MATCH_CASEINSENSITIVE, /* case matching */
|
||||
FALSE); /* use_regexp */
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_CHAR))
|
||||
{
|
||||
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))
|
||||
{
|
||||
gint32 ival = atoi (qvalue_name);
|
||||
pred_data = qof_query_int32_predicate (qop, ival);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_INT64))
|
||||
{
|
||||
gint64 ival = atoll (qvalue_name);
|
||||
pred_data = qof_query_int64_predicate (qop, ival);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
|
||||
{
|
||||
double ival = atof (qvalue_name);
|
||||
pred_data = qof_query_double_predicate (qop, ival);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* Use a timezone independent setting */
|
||||
qof_date_format_set(QOF_DATE_FORMAT_UTC);
|
||||
rc = 0;
|
||||
if (FALSE == qof_scan_date_secs (qvalue_name, &exact))
|
||||
{
|
||||
char *tail;
|
||||
exact = strtoll(qvalue_name, &tail, 0);
|
||||
// PWARN ("unable to parse date: %s", qvalue_name);
|
||||
// return NULL;
|
||||
}
|
||||
ts.tv_sec = exact;
|
||||
ts.tv_nsec = 0;
|
||||
pred_data = qof_query_date_predicate (qop, QOF_DATE_MATCH_NORMAL, ts);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
|
||||
{
|
||||
gnc_numeric ival;
|
||||
string_to_gnc_numeric (qvalue_name, &ival);
|
||||
pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
|
||||
{
|
||||
// XXX this probably needs some work ...
|
||||
gnc_numeric ival;
|
||||
string_to_gnc_numeric (qvalue_name, &ival);
|
||||
pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_GUID))
|
||||
{
|
||||
GncGUID guid;
|
||||
gboolean rc = string_to_guid (qvalue_name, &guid);
|
||||
if (0 == rc)
|
||||
{
|
||||
PWARN ("unable to parse guid: %s", qvalue_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// XXX less, than greater than don't make sense,
|
||||
// should check for those bad conditions
|
||||
|
||||
gm = QOF_GUID_MATCH_ANY;
|
||||
if (QOF_COMPARE_NEQ == qop) gm = QOF_GUID_MATCH_NONE;
|
||||
guid_list = g_list_append (NULL, &guid);
|
||||
pred_data = qof_query_guid_predicate (gm, guid_list);
|
||||
|
||||
g_list_free (guid_list);
|
||||
}
|
||||
else if (!strcmp (param_type, QOF_TYPE_KVP))
|
||||
{
|
||||
/* We are expecting an encoded value that looks like
|
||||
* /some/path/string:value
|
||||
*/
|
||||
sep = strchr (qvalue_name, ':');
|
||||
if (!sep) return NULL;
|
||||
*sep = 0;
|
||||
path = qvalue_name;
|
||||
str = sep + 1;
|
||||
/* 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 GncGUID
|
||||
* If it looks like an iso date ...
|
||||
* else assume its a string.
|
||||
*/
|
||||
kval = NULL;
|
||||
len = strlen (str);
|
||||
if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
|
||||
{
|
||||
GncGUID 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
PWARN ("The predicate type \"%s\" is unsupported for now", param_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qq = qof_query_create();
|
||||
qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
|
||||
return qq;
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
static QofQuery *
|
||||
handle_where (QofSqlQuery *query, sql_where *swear)
|
||||
{
|
||||
QofQueryOp qop;
|
||||
QofQuery * qq;
|
||||
|
||||
switch (swear->type)
|
||||
{
|
||||
case SQL_pair:
|
||||
{
|
||||
QofQuery *qleft = handle_where (query, swear->d.pair.left);
|
||||
QofQuery *qright = handle_where (query, swear->d.pair.right);
|
||||
if (NULL == qleft) return qright;
|
||||
if (NULL == qright) return qleft;
|
||||
switch (swear->d.pair.op)
|
||||
{
|
||||
case SQL_and:
|
||||
qop = QOF_QUERY_AND;
|
||||
break;
|
||||
case SQL_or:
|
||||
qop = QOF_QUERY_OR;
|
||||
break;
|
||||
/* XXX should add support for nand, nor, xor */
|
||||
default:
|
||||
qof_query_destroy (qleft);
|
||||
qof_query_destroy (qright);
|
||||
return NULL;
|
||||
}
|
||||
qq = qof_query_merge (qleft, qright, qop);
|
||||
qof_query_destroy (qleft);
|
||||
qof_query_destroy (qright);
|
||||
return qq;
|
||||
}
|
||||
case SQL_negated:
|
||||
{
|
||||
QofQuery *qq = handle_where (query, swear->d.negated);
|
||||
QofQuery *qneg = qof_query_invert (qq);
|
||||
qof_query_destroy (qq);
|
||||
return qneg;
|
||||
}
|
||||
|
||||
case SQL_single:
|
||||
{
|
||||
sql_condition * cond = swear->d.single;
|
||||
return handle_single_condition (query, cond);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
static void
|
||||
handle_sort_order (QofSqlQuery *query, GList *sorder_list)
|
||||
{
|
||||
GSList *qsp[3];
|
||||
GList *n;
|
||||
gboolean direction[3];
|
||||
int i;
|
||||
sql_order_field *sorder;
|
||||
char * qparam_name;
|
||||
|
||||
if (!sorder_list) return;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
qsp[i] = NULL;
|
||||
direction[i] = 0;
|
||||
|
||||
if (sorder_list)
|
||||
{
|
||||
sorder = sorder_list->data;
|
||||
|
||||
/* Set the sort direction */
|
||||
if (SQL_asc == sorder->order_type) direction[i] = TRUE;
|
||||
|
||||
/* Find the parameter name */
|
||||
qparam_name = NULL;
|
||||
n = sorder->name;
|
||||
if (n)
|
||||
{
|
||||
qparam_name = n->data;
|
||||
if (qparam_name)
|
||||
{
|
||||
qsp[i] = qof_query_build_param_list (qparam_name, NULL);
|
||||
}
|
||||
n = n->next; /* next parameter */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if no next parameter, then next order-by */
|
||||
sorder_list = sorder_list->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
|
||||
qof_query_set_sort_increasing (query->qof_query, direction[0],
|
||||
direction[1], direction[2]);
|
||||
}
|
||||
|
||||
/* INSERT INTO handlers =================================================== */
|
||||
|
||||
static void
|
||||
qof_sql_insertCB(const QofParam *param, const gchar *insert_string, QofSqlQuery *query)
|
||||
{
|
||||
QofIdTypeConst type;
|
||||
sql_insert_statement *sis;
|
||||
gboolean registered_type;
|
||||
QofInstance *ent;
|
||||
struct tm query_time;
|
||||
time_t query_time_t;
|
||||
/* cm_ prefix used for variables that hold the data to commit */
|
||||
gnc_numeric cm_numeric;
|
||||
double cm_double;
|
||||
gboolean cm_boolean;
|
||||
gint32 cm_i32;
|
||||
gint64 cm_i64;
|
||||
Timespec cm_date;
|
||||
char cm_char, *tail;
|
||||
GncGUID *cm_guid;
|
||||
/* KvpFrame *cm_kvp;
|
||||
KvpValue *cm_value;
|
||||
KvpValueType cm_type;*/
|
||||
void (*string_setter) (QofInstance*, const char*);
|
||||
void (*date_setter) (QofInstance*, Timespec);
|
||||
void (*numeric_setter) (QofInstance*, gnc_numeric);
|
||||
void (*double_setter) (QofInstance*, double);
|
||||
void (*boolean_setter) (QofInstance*, gboolean);
|
||||
void (*i32_setter) (QofInstance*, gint32);
|
||||
void (*i64_setter) (QofInstance*, gint64);
|
||||
void (*char_setter) (QofInstance*, char);
|
||||
/* void (*kvp_frame_setter) (QofInstance*, KvpFrame*);*/
|
||||
|
||||
g_return_if_fail(param || insert_string || query);
|
||||
ent = query->inserted_entity;
|
||||
sis = query->parse_result->statement;
|
||||
type = g_strdup_printf("%s", sis->table->d.simple);
|
||||
|
||||
ENTER (" param=%s param_type=%s type=%s content=%s",
|
||||
param->param_name, param->param_type, type, insert_string);
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_STRING) == 0)
|
||||
{
|
||||
string_setter = (void(*)(QofInstance*, const char*))param->param_setfcn;
|
||||
if (string_setter != NULL)
|
||||
{
|
||||
string_setter(ent, insert_string);
|
||||
}
|
||||
registered_type = TRUE;
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_DATE) == 0)
|
||||
{
|
||||
date_setter = (void(*)(QofInstance*, Timespec))param->param_setfcn;
|
||||
strptime(insert_string, QOF_UTC_DATE_FORMAT, &query_time);
|
||||
query_time_t = mktime(&query_time);
|
||||
timespecFromTime_t(&cm_date, query_time_t);
|
||||
if (date_setter != NULL)
|
||||
{
|
||||
date_setter(ent, cm_date);
|
||||
}
|
||||
}
|
||||
if ((safe_strcmp(param->param_type, QOF_TYPE_NUMERIC) == 0) ||
|
||||
(safe_strcmp(param->param_type, QOF_TYPE_DEBCRED) == 0))
|
||||
{
|
||||
numeric_setter = (void(*)(QofInstance*, gnc_numeric))param->param_setfcn;
|
||||
string_to_gnc_numeric(insert_string, &cm_numeric);
|
||||
if (numeric_setter != NULL)
|
||||
{
|
||||
numeric_setter(ent, cm_numeric);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_GUID) == 0)
|
||||
{
|
||||
cm_guid = g_new(GncGUID, 1);
|
||||
if (TRUE != string_to_guid(insert_string, cm_guid))
|
||||
{
|
||||
LEAVE (" string to guid failed for %s", insert_string);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_INT32) == 0)
|
||||
{
|
||||
errno = 0;
|
||||
cm_i32 = (gint32)strtol (insert_string, &tail, 0);
|
||||
if (errno == 0)
|
||||
{
|
||||
i32_setter = (void(*)(QofInstance*, gint32))param->param_setfcn;
|
||||
if (i32_setter != NULL)
|
||||
{
|
||||
i32_setter(ent, cm_i32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QofBackend *backend;
|
||||
QofBook *book;
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QOF_OVERFLOW);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_INT64) == 0)
|
||||
{
|
||||
errno = 0;
|
||||
cm_i64 = strtoll(insert_string, &tail, 0);
|
||||
if (errno == 0)
|
||||
{
|
||||
i64_setter = (void(*)(QofInstance*, gint64))param->param_setfcn;
|
||||
if (i64_setter != NULL)
|
||||
{
|
||||
i64_setter(ent, cm_i64);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QofBackend *backend;
|
||||
QofBook *book;
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QOF_OVERFLOW);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_DOUBLE) == 0)
|
||||
{
|
||||
errno = 0;
|
||||
cm_double = strtod(insert_string, &tail);
|
||||
if (errno == 0)
|
||||
{
|
||||
double_setter = (void(*)(QofInstance*, double))param->param_setfcn;
|
||||
if (double_setter != NULL)
|
||||
{
|
||||
double_setter(ent, cm_double);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_BOOLEAN) == 0)
|
||||
{
|
||||
gint b;
|
||||
b = qof_util_bool_to_int(insert_string);
|
||||
if (b == 1)
|
||||
{
|
||||
cm_boolean = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
cm_boolean = FALSE;
|
||||
}
|
||||
boolean_setter = (void(*)(QofInstance*, gboolean))param->param_setfcn;
|
||||
if (boolean_setter != NULL)
|
||||
{
|
||||
boolean_setter(ent, cm_boolean);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_KVP) == 0)
|
||||
{
|
||||
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_CHAR) == 0)
|
||||
{
|
||||
cm_char = *insert_string;
|
||||
char_setter = (void(*)(QofInstance*, char))param->param_setfcn;
|
||||
if (char_setter != NULL)
|
||||
{
|
||||
char_setter(ent, cm_char);
|
||||
}
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
qof_query_set_insert_table(QofSqlQuery *query)
|
||||
{
|
||||
sql_insert_statement *sis;
|
||||
sql_table *sis_t;
|
||||
sis = query->parse_result->statement;
|
||||
switch (sis->table->type)
|
||||
{
|
||||
case SQL_simple:
|
||||
{
|
||||
sis_t = sis->table;
|
||||
query->single_global_tablename = g_strdup_printf("%s", sis_t->d.simple);
|
||||
qof_query_search_for (query->qof_query, query->single_global_tablename);
|
||||
PINFO (" insert set to table: %s", sis_t->d.simple);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
PWARN ("SQL insert only handles simple statements");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QofInstance*
|
||||
qof_query_insert(QofSqlQuery *query)
|
||||
{
|
||||
GList *field_list, *value_list, *cur;
|
||||
const gchar *param_name;
|
||||
gchar *value;
|
||||
QofIdType type;
|
||||
const QofParam *param;
|
||||
QofInstance *inst;
|
||||
sql_insert_statement *sis;
|
||||
sql_field *field;
|
||||
sql_field_item *item;
|
||||
|
||||
ENTER (" ");
|
||||
query->param_list = NULL;
|
||||
type = NULL;
|
||||
param = NULL;
|
||||
value = NULL;
|
||||
field_list = NULL;
|
||||
value_list = NULL;
|
||||
param_name = NULL;
|
||||
sis = query->parse_result->statement;
|
||||
if (!sis->fields || !sis->values)
|
||||
{
|
||||
LEAVE (" NULL insert statement");
|
||||
return NULL;
|
||||
}
|
||||
type = g_strdup(query->single_global_tablename);
|
||||
inst = (QofInstance*)qof_object_new_instance(type, query->book);
|
||||
if (inst == NULL)
|
||||
{
|
||||
LEAVE (" unable to create instance of type %s", type);
|
||||
return NULL;
|
||||
}
|
||||
query->inserted_entity = inst;
|
||||
value_list = sis->values;
|
||||
for (field_list = sis->fields; field_list != NULL; field_list = field_list->next)
|
||||
{
|
||||
field = value_list->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
value = g_strdup_printf("%s", dequote_string((char*)cur->data));
|
||||
}
|
||||
field = field_list->data;
|
||||
item = field->item;
|
||||
for (cur = item->d.name; cur != NULL; cur = cur->next)
|
||||
{
|
||||
param_name = g_strdup_printf("%s", (char*)cur->data);
|
||||
param = qof_class_get_parameter(type, param_name);
|
||||
}
|
||||
if (param && value)
|
||||
{
|
||||
qof_sql_insertCB(param, value, query);
|
||||
}
|
||||
value_list = g_list_next(value_list);
|
||||
}
|
||||
LEAVE (" ");
|
||||
return query->inserted_entity;
|
||||
}
|
||||
|
||||
static const char*
|
||||
sql_type_as_string(sql_statement_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SQL_select :
|
||||
{
|
||||
return "SELECT";
|
||||
}
|
||||
case SQL_insert :
|
||||
{
|
||||
return "INSERT";
|
||||
}
|
||||
case SQL_delete :
|
||||
{
|
||||
return "DELETE";
|
||||
}
|
||||
case SQL_update :
|
||||
{
|
||||
return "UPDATE";
|
||||
}
|
||||
default :
|
||||
{
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qof_sql_query_parse (QofSqlQuery *query, const char *str)
|
||||
{
|
||||
GList *tables;
|
||||
char *buf;
|
||||
sql_select_statement *sss;
|
||||
sql_where *swear;
|
||||
|
||||
if (!query) return;
|
||||
ENTER (" ");
|
||||
/* Delete old query, if any */
|
||||
if (query->qof_query)
|
||||
{
|
||||
qof_query_destroy (query->qof_query);
|
||||
sql_destroy(query->parse_result);
|
||||
query->qof_query = NULL;
|
||||
}
|
||||
|
||||
/* Parse the SQL string */
|
||||
buf = g_strdup(str);
|
||||
query->parse_result = sql_parse (buf);
|
||||
g_free(buf);
|
||||
|
||||
if (!query->parse_result)
|
||||
{
|
||||
LEAVE ("parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((SQL_select != query->parse_result->type) && (SQL_insert != query->parse_result->type))
|
||||
{
|
||||
LEAVE ("currently, only SELECT or INSERT statements are supported, "
|
||||
"got type=%s", sql_type_as_string(query->parse_result->type));
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the user wrote "SELECT * FROM tablename WHERE ..."
|
||||
* then we have a single global tablename. But if the
|
||||
* user wrote "SELECT * FROM tableA, tableB WHERE ..."
|
||||
* then we don't have a single unique table-name.
|
||||
*/
|
||||
tables = sql_statement_get_tables (query->parse_result);
|
||||
if (1 == g_list_length (tables))
|
||||
{
|
||||
query->single_global_tablename = tables->data;
|
||||
}
|
||||
/* if this is an insert, we're done with the parse. */
|
||||
if (SQL_insert == query->parse_result->type)
|
||||
{
|
||||
query->qof_query = qof_query_create();
|
||||
qof_query_set_insert_table(query);
|
||||
LEAVE (" insert statement parsed OK");
|
||||
return;
|
||||
}
|
||||
sss = query->parse_result->statement;
|
||||
swear = sss->where;
|
||||
if (swear)
|
||||
{
|
||||
/* Walk over the where terms, turn them into QOF predicates */
|
||||
query->qof_query = handle_where (query, swear);
|
||||
if (NULL == query->qof_query)
|
||||
{
|
||||
LEAVE (" no query found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
query->qof_query = qof_query_create();
|
||||
}
|
||||
/* Provide support for different sort orders */
|
||||
handle_sort_order (query, sss->order);
|
||||
|
||||
/* We also want to set the type of thing to search for.
|
||||
* SELECT * FROM table1, table2, ... is not supported.
|
||||
* Use sequential queries and build a partial book.
|
||||
*/
|
||||
qof_query_search_for (query->qof_query, query->single_global_tablename);
|
||||
LEAVE (" success");
|
||||
}
|
||||
|
||||
/* ========================================================== */
|
||||
|
||||
GList *
|
||||
qof_sql_query_run (QofSqlQuery *query, const char *str)
|
||||
{
|
||||
GList *results;
|
||||
|
||||
if (!query) return NULL;
|
||||
|
||||
qof_sql_query_parse (query, str);
|
||||
if (NULL == query->qof_query)
|
||||
{
|
||||
PINFO (" Null query");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qof_query_set_book (query->qof_query, query->book);
|
||||
/* Maybe log this sucker */
|
||||
if (qof_should_log (log_module, QOF_LOG_DEBUG))
|
||||
{
|
||||
qof_query_print (query->qof_query);
|
||||
}
|
||||
if (SQL_insert == query->parse_result->type)
|
||||
{
|
||||
results = NULL;
|
||||
results = g_list_append(results, qof_query_insert(query));
|
||||
return results;
|
||||
}
|
||||
|
||||
results = qof_query_run (query->qof_query);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
GList *
|
||||
qof_sql_query_rerun (QofSqlQuery *query)
|
||||
{
|
||||
GList *results;
|
||||
|
||||
if (!query) return NULL;
|
||||
|
||||
if (NULL == query->qof_query) return NULL;
|
||||
|
||||
qof_query_set_book (query->qof_query, query->book);
|
||||
|
||||
/* Maybe log this sucker */
|
||||
if (qof_should_log (log_module, QOF_LOG_DEBUG))
|
||||
{
|
||||
qof_query_print (query->qof_query);
|
||||
}
|
||||
|
||||
results = qof_query_run (query->qof_query);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/* ========================== END OF FILE =================== */
|
@ -1,200 +0,0 @@
|
||||
/********************************************************************\
|
||||
* qofsql.h -- QOF client-side SQL parser using libgda *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
\********************************************************************/
|
||||
|
||||
/** @addtogroup Query
|
||||
@{ */
|
||||
/**
|
||||
@file qofsql.h
|
||||
@brief QOF client-side SQL parser, interfacing with libgda.
|
||||
@author Copyright (C) 2004 Linas Vepstas <linas@linas.org>
|
||||
*/
|
||||
|
||||
#ifndef QOF_SQL_QUERY_H
|
||||
#define QOF_SQL_QUERY_H
|
||||
|
||||
#include "kvp_frame.h"
|
||||
#include "qofbook.h"
|
||||
#include "qofquery.h"
|
||||
|
||||
/** @addtogroup SQL SQL Interface to Query
|
||||
|
||||
The types of SQL queries that are allowed at this point are very
|
||||
limited. In general, only the following types of queries are
|
||||
supported:
|
||||
SELECT * FROM SomeObj WHERE (param_a < 10.0) AND (param_b = "asdf")
|
||||
SORT BY param_c DESC;
|
||||
INSERT INTO SomeObj (param_a, param_b, param_c) VALUES
|
||||
("value_a", true, "0/1");
|
||||
|
||||
For SELECT, the returned list is a list of all of the instances of 'SomeObj' that
|
||||
match the query. The 'SORT' term is optional. The 'WHERE' term is
|
||||
optional; but if you don't include 'WHERE', you will get a list of
|
||||
all of the object instances. The Boolean operations 'AND' and 'OR'
|
||||
together with parenthesis can be used to construct arbitrarily
|
||||
nested predicates.
|
||||
|
||||
For INSERT, the returned list is a list containing the newly created instance
|
||||
of 'SomeObj'.
|
||||
|
||||
Joins are not supported directly.
|
||||
SELECT * FROM ObjA,ObjB WHERE (ObjA.param_id = ObjB.param_other_id);
|
||||
The problem with the above is that the search requires a nested
|
||||
search loop, aka a 'join', which is not currently supported in the
|
||||
underlying QofQuery code.
|
||||
|
||||
However, by repeating queries and adding the entities to a new session using
|
||||
::qof_instance_copy_list, a series of queries can be added to a single
|
||||
book. e.g. You can insert multiple entities and save out as a QSF XML
|
||||
file or use multiple SELECT queries to build a precise list - this
|
||||
can be used to replicate most of the functionality of a SQL join.
|
||||
|
||||
SELECT * from ObjA where param_id = value;
|
||||
SELECT * from ObjB where param_other_id = value;
|
||||
|
||||
Equivalent to:
|
||||
SELECT * from ObjA,ObjB where param_id = param_other_id and param_id = value;
|
||||
|
||||
When combined with a foreach callback on the value of param_id for each
|
||||
entity in the QofBook, you can produce the effect of a join from running
|
||||
the two SELECT queries for each value of param_id held in 'value'.
|
||||
|
||||
See ::QofInstanceForeachCB and ::qof_object_foreach.
|
||||
|
||||
Date queries handle full date and time strings, using the format
|
||||
exported by the QSF backend. To query dates and times, convert
|
||||
user input into UTC time using the ::QOF_UTC_DATE_FORMAT string.
|
||||
e.g. set the UTC date format and call ::qof_print_time_buff
|
||||
with a time_t obtained via ::timespecToTime_t.
|
||||
|
||||
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
|
||||
whose keys would be a,b,c and values would be the results of the
|
||||
search. (Linas)
|
||||
|
||||
XXX (Neil W). Alternatively, I need to use something like this
|
||||
when converting QOF objects between applications by using the
|
||||
returned parameter values to create a second object. One application
|
||||
using QOF could register objects from two applications and convert
|
||||
data from one to the other by using SELECT a,b,c FROM ObjA;
|
||||
SELECT d,f,k FROM ObjB; qof_object_new_instance(); ObjC_set_a(value_c);
|
||||
ObjC_set_b(value_k) etc. What's needed is for the SELECT to return
|
||||
a complete object that only contains the parameters selected.
|
||||
|
||||
Also unsupported: UPDATE.
|
||||
|
||||
Certain SQL commands can have no QOF equivalent and will
|
||||
generate a runtime parser error:
|
||||
- ALTER
|
||||
- CREATE
|
||||
- DROP
|
||||
- FLUSH
|
||||
- GRANT
|
||||
- KILL
|
||||
- LOCK
|
||||
- OPTIMIZE
|
||||
- REVOKE
|
||||
- USE
|
||||
|
||||
@{ */
|
||||
typedef struct _QofSqlQuery QofSqlQuery;
|
||||
|
||||
/** Create a new SQL-syntax query machine.
|
||||
*/
|
||||
QofSqlQuery * qof_sql_query_new (void);
|
||||
void qof_sql_query_destroy (QofSqlQuery *);
|
||||
|
||||
/** Set the book to be searched (you can search multiple books)
|
||||
* If no books are set, no results will be returned (since there
|
||||
* is nothing to search over).
|
||||
*/
|
||||
void qof_sql_query_set_book (QofSqlQuery *q, QofBook *book);
|
||||
|
||||
/** \brief Perform the query, return the results.
|
||||
|
||||
* The book must be set in order to be able to perform a query.
|
||||
*
|
||||
* The returned list will have been sorted using the indicated sort
|
||||
* order, (by default ascending order) and trimmed to the
|
||||
* max_results length.
|
||||
* Do NOT free the resulting list. This list is managed internally
|
||||
* by QofSqlQuery.
|
||||
*
|
||||
*/
|
||||
|
||||
GList * qof_sql_query_run (QofSqlQuery *query, const gchar * str);
|
||||
|
||||
/** Same ::qof_sql_query_run, 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 gchar * 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.
|
||||
*
|
||||
* Although joins are not supported (see above), there is one special
|
||||
* hack that one can use to pass data indirectly into the predicates.
|
||||
* This is by using a KVP key name to reference the value to be used
|
||||
* for a predicate. Thus, for example,
|
||||
* SELECT * FROM SomeObj WHERE (param_a = KVP:/some/key/path);
|
||||
* will look up the value stored at '/some/key/path', and use that
|
||||
* value to form the actual predicate. So, for example, if
|
||||
* the value stored at '/some/key/path' was 2, then the actual
|
||||
* query run will be
|
||||
* SELECT * FROM SomeObj WHERE (param_a = 2);
|
||||
* The lookup occurs at the time that the query is formulated.
|
||||
*
|
||||
* The query does *not* take over ownership of the kvp frame,
|
||||
* nor does it copy it. Thus, the kvp frame must exist when the
|
||||
* query is formulated, and it is the responsibility of the
|
||||
* caller to free it when no longer needed.
|
||||
*
|
||||
* Note that because this feature is a kind of a hack put in place
|
||||
* due to the lack of support for joins, it will probably go away
|
||||
* (be deprecated) if/when joins are implemented.
|
||||
*/
|
||||
void qof_sql_query_set_kvp (QofSqlQuery *, KvpFrame *);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
#endif /* QOF_SQL_QUERY_H */
|
Loading…
Reference in New Issue
Block a user