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:
Christian Stimming 2011-04-02 19:02:05 +00:00
parent 683b7a6bbb
commit aaa2410309
9 changed files with 0 additions and 2662 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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"

View File

@ -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 =================== */

View 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 */

View File

@ -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 =================== */

View 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 */

View File

@ -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, &param_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 =================== */

View 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 */