qofsql.c

Go to the documentation of this file.
00001 /********************************************************************\
00002  * qofsql.c -- QOF client-side SQL parser                           *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020  *                                                                  *
00021 \********************************************************************/
00022 
00030 #include "config.h"
00031 #include <stdlib.h>             /* for working atoll */
00032 #include <errno.h>
00033 #include <glib.h>
00034 #include <libintl.h>
00035 #ifdef HAVE_GDA
00036 #include <libsql/sql_parser.h>
00037 #else
00038 #include "sql_parser.h"
00039 #endif
00040 #include <time.h>
00041 #include "qof.h"
00042 #include "qofquery-p.h"
00043 
00044 #define _(String) dgettext (GETTEXT_PACKAGE, String)
00045 
00046 static QofLogModule log_module = QOF_MOD_QUERY;
00047 
00048 /* =================================================================== */
00049 
00050 struct _QofSqlQuery
00051 {
00052     sql_statement *parse_result;
00053     QofQuery *qof_query;
00054     QofBook *book;
00055     gchar *single_global_tablename;
00056     KvpFrame *kvp_join;
00057     GList *param_list;
00058     QofEntity *inserted_entity;
00059 };
00060 
00061 /* ========================================================== */
00062 
00063 QofSqlQuery *
00064 qof_sql_query_new (void)
00065 {
00066     QofSqlQuery *sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
00067 
00068     sqn->qof_query = NULL;
00069     sqn->parse_result = NULL;
00070     sqn->book = NULL;
00071     sqn->single_global_tablename = NULL;
00072     sqn->kvp_join = NULL;
00073 
00074     return sqn;
00075 }
00076 
00077 /* ========================================================== */
00078 
00079 void
00080 qof_sql_query_destroy (QofSqlQuery * q)
00081 {
00082     if (!q)
00083         return;
00084     qof_query_destroy (q->qof_query);
00085     sql_destroy (q->parse_result);
00086     g_free (q);
00087 }
00088 
00089 /* ========================================================== */
00090 
00091 QofQuery *
00092 qof_sql_query_get_query (QofSqlQuery * q)
00093 {
00094     if (!q)
00095         return NULL;
00096     return q->qof_query;
00097 }
00098 
00099 /* ========================================================== */
00100 
00101 void
00102 qof_sql_query_set_book (QofSqlQuery * q, QofBook * book)
00103 {
00104     if (!q)
00105         return;
00106     q->book = book;
00107 }
00108 
00109 /* ========================================================== */
00110 
00111 void
00112 qof_sql_query_set_kvp (QofSqlQuery * q, KvpFrame * kvp)
00113 {
00114     if (!q)
00115         return;
00116     q->kvp_join = kvp;
00117 }
00118 
00119 /* ========================================================== */
00120 
00121 static inline void
00122 get_table_and_param (char *str, char **tab, char **param)
00123 {
00124     char *end = strchr (str, '.');
00125     if (!end)
00126     {
00127         *tab = 0;
00128         *param = str;
00129         return;
00130     }
00131     *end = 0;
00132     *tab = str;
00133     *param = end + 1;
00134 }
00135 
00136 static inline char *
00137 dequote_string (char *str)
00138 {
00139     size_t len;
00140     /* strip out quotation marks ...  */
00141     if (('\'' == str[0]) || ('\"' == str[0]))
00142     {
00143         str++;
00144         len = strlen (str);
00145         str[len - 1] = 0;
00146     }
00147     return str;
00148 }
00149 
00150 static QofQuery *
00151 handle_single_condition (QofSqlQuery * query, sql_condition * cond)
00152 {
00153     char tmpbuff[128];
00154     GSList *param_list;
00155     GList *guid_list;
00156     QofQueryPredData *pred_data;
00157     sql_field_item *sparam, *svalue;
00158     gchar *qparam_name, *qvalue_name, *table_name, *param_name;
00159     gchar *sep, *path, *str, *p;
00160     QofQuery *qq;
00161     KvpValue *kv, *kval;
00162     KvpValueType kvt;
00163     QofQueryCompare qop;
00164     guint len;
00165     QofType param_type;
00166     QofGuidMatch gm;
00167 
00168     pred_data = NULL;
00169     if (NULL == cond)
00170     {
00171         PWARN ("missing condition");
00172         return NULL;
00173     }
00174     /* -------------------------------- */
00175     /* field to match, assumed, for now to be on the left */
00176     /* XXX fix this so it can be either left or right */
00177     if (NULL == cond->d.pair.left)
00178     {
00179         PWARN ("missing left parameter");
00180         return NULL;
00181     }
00182     sparam = cond->d.pair.left->item;
00183     if (SQL_name != sparam->type)
00184     {
00185         PWARN ("we support only parameter names at this time (parsed %d)",
00186             sparam->type);
00187         return NULL;
00188     }
00189     qparam_name = sparam->d.name->data;
00190     if (NULL == qparam_name)
00191     {
00192         PWARN ("missing parameter name");
00193         return NULL;
00194     }
00195 
00196     /* -------------------------------- */
00197     /* value to match, assumed, for now, to be on the right. */
00198     /* XXX fix this so it can be either left or right */
00199     if (NULL == cond->d.pair.right)
00200     {
00201         PWARN ("missing right parameter");
00202         return NULL;
00203     }
00204     svalue = cond->d.pair.right->item;
00205     if (SQL_name != svalue->type)
00206     {
00207         PWARN ("we support only simple values (parsed as %d)",
00208             svalue->type);
00209         return NULL;
00210     }
00211     qvalue_name = svalue->d.name->data;
00212     if (NULL == qvalue_name)
00213     {
00214         PWARN ("missing value");
00215         return NULL;
00216     }
00217     qvalue_name = dequote_string (qvalue_name);
00218     qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
00219 
00220     /* Look to see if its the special KVP value holder.
00221      * If it is, look up the value. */
00222     if (0 == strncasecmp (qvalue_name, "kvp://", 6))
00223     {
00224         if (NULL == query->kvp_join)
00225         {
00226             PWARN ("missing kvp frame");
00227             return NULL;
00228         }
00229         kv = kvp_frame_get_value (query->kvp_join, qvalue_name + 5);
00230         /* If there's no value, its not an error; 
00231          * we just don't do this predicate */
00232         if (!kv)
00233             return NULL;
00234         kvt = kvp_value_get_type (kv);
00235 
00236         tmpbuff[0] = 0x0;
00237         qvalue_name = tmpbuff;
00238         switch (kvt)
00239         {
00240         case KVP_TYPE_GINT64:
00241         {
00242                 gint64 ival = kvp_value_get_gint64 (kv);
00243                 sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival);
00244                 break;
00245         }
00246         case KVP_TYPE_DOUBLE:
00247         {
00248                 double ival = kvp_value_get_double (kv);
00249                 sprintf (tmpbuff, "%26.18g\n", ival);
00250                 break;
00251         }
00252         case KVP_TYPE_STRING:
00253             /* If there's no value, its not an error; 
00254              * we just don't do this predicate */
00255             qvalue_name = kvp_value_get_string (kv);
00256             if (!qvalue_name)
00257                 return NULL;
00258             break;
00259         case KVP_TYPE_GUID:
00260         case KVP_TYPE_TIME :
00261 #ifndef QOF_DISABLE_DEPRECATED
00262         case KVP_TYPE_TIMESPEC:
00263 #endif
00264         case KVP_TYPE_BOOLEAN :
00265         case KVP_TYPE_BINARY:
00266         case KVP_TYPE_GLIST:
00267         case KVP_TYPE_NUMERIC:
00268         case KVP_TYPE_FRAME:
00269             PWARN ("unhandled kvp type=%d", kvt);
00270             return NULL;
00271         }
00272     }
00273 
00274     /* -------------------------------- */
00275     /* Now start building the QOF parameter */
00276     param_list = qof_query_build_param_list (qparam_name, NULL);
00277 
00278     /* Get the where-term comparison operator */
00279     switch (cond->op)
00280     {
00281     case SQL_eq:
00282         qop = QOF_COMPARE_EQUAL;
00283         break;
00284     case SQL_gt:
00285         qop = QOF_COMPARE_GT;
00286         break;
00287     case SQL_lt:
00288         qop = QOF_COMPARE_LT;
00289         break;
00290     case SQL_geq:
00291         qop = QOF_COMPARE_GTE;
00292         break;
00293     case SQL_leq:
00294         qop = QOF_COMPARE_LTE;
00295         break;
00296     case SQL_diff:
00297         qop = QOF_COMPARE_NEQ;
00298         break;
00299     default:
00300         /* XXX for string-type queries, we should be able to
00301          * support 'IN' for substring search.  Also regex. */
00302         PWARN ("Unsupported compare op (parsed as %u)", cond->op);
00303         return NULL;
00304     }
00305 
00306     /* OK, need to know the type of the thing being matched 
00307      * in order to build the correct predicate.  Get the type 
00308      * from the object parameters. */
00309     get_table_and_param (qparam_name, &table_name, &param_name);
00310     if (NULL == table_name)
00311     {
00312         table_name = query->single_global_tablename;
00313     }
00314     if (NULL == table_name)
00315     {
00316         PWARN ("Need to specify an object class to query");
00317         return NULL;
00318     }
00319 
00320     if (FALSE == qof_class_is_registered (table_name))
00321     {
00322         PWARN ("The query object \'%s\' is not known", table_name);
00323         return NULL;
00324     }
00325 
00326     param_type = qof_class_get_parameter_type (table_name, param_name);
00327     if (!param_type)
00328     {
00329         PWARN ("The parameter \'%s\' on object \'%s\' is not known",
00330             param_name, table_name);
00331         return NULL;
00332     }
00333 
00334     if (!strcmp (param_type, QOF_TYPE_STRING))
00335     {
00336         pred_data = qof_query_string_predicate (qop,    /* comparison to make */
00337             qvalue_name,        /* string to match */
00338             QOF_STRING_MATCH_CASEINSENSITIVE,   /* case matching */
00339             FALSE);             /* use_regexp */
00340     }
00341     else if (!strcmp (param_type, QOF_TYPE_CHAR))
00342     {
00343         QofCharMatch cm = QOF_CHAR_MATCH_ANY;
00344         if (QOF_COMPARE_NEQ == qop)
00345             cm = QOF_CHAR_MATCH_NONE;
00346         pred_data = qof_query_char_predicate (cm, qvalue_name);
00347     }
00348     else if (!strcmp (param_type, QOF_TYPE_INT32))
00349     {
00350         gint32 ival = atoi (qvalue_name);
00351         pred_data = qof_query_int32_predicate (qop, ival);
00352     }
00353     else if (!strcmp (param_type, QOF_TYPE_INT64))
00354     {
00355         gint64 ival = atoll (qvalue_name);
00356         pred_data = qof_query_int64_predicate (qop, ival);
00357     }
00358     else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
00359     {
00360         double ival = atof (qvalue_name);
00361         pred_data = qof_query_double_predicate (qop, ival);
00362     }
00363     else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
00364     {
00365         gboolean ival = qof_util_bool_to_int (qvalue_name);
00366         pred_data = qof_query_boolean_predicate (qop, ival);
00367     }
00368     else if (!safe_strcmp (param_type, QOF_TYPE_TIME))
00369     {
00370         QofDate *qd;
00371         QofTime *qt;
00372 
00373         qd = qof_date_parse (qvalue_name, QOF_DATE_FORMAT_UTC);
00374         qt = qof_date_to_qtime (qd);
00375         qof_date_free (qd);
00376         pred_data = 
00377             qof_query_time_predicate (qop, QOF_DATE_MATCH_NORMAL, 
00378             qt);
00379     }
00380 #ifndef QOF_DISABLE_DEPRECATED
00381     else if (!strcmp (param_type, QOF_TYPE_DATE))
00382     {
00383         gint rc;
00384         Timespec ts;
00385         time_t exact;
00386 
00387         /* Use a timezone independent setting */
00388         qof_date_format_set (QOF_DATE_FORMAT_UTC);
00389         rc = 0;
00390         if (FALSE == qof_scan_date_secs (qvalue_name, &exact))
00391         {
00392             char *tail;
00393             exact = strtoll (qvalue_name, &tail, 0);
00394 //          PWARN ("unable to parse date: %s", qvalue_name);
00395 //          return NULL;
00396         }
00397         ts.tv_sec = exact;
00398         ts.tv_nsec = 0;
00399         pred_data =
00400             qof_query_date_predicate (qop, QOF_DATE_MATCH_NORMAL, ts);
00401     }
00402 #endif
00403     else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
00404     {
00405         QofNumeric ival;
00406         qof_numeric_from_string (qvalue_name, &ival);
00407         pred_data =
00408             qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
00409     }
00410     else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
00411     {
00412         /* DEBCRED is likely to be deprecated before libqof2 */
00413         QofNumeric ival;
00414         qof_numeric_from_string (qvalue_name, &ival);
00415         pred_data =
00416             qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
00417     }
00418     else if (!strcmp (param_type, QOF_TYPE_GUID))
00419     {
00420         GUID guid;
00421         gboolean rc = string_to_guid (qvalue_name, &guid);
00422         if (0 == rc)
00423         {
00424             PWARN ("unable to parse guid: %s", qvalue_name);
00425             return NULL;
00426         }
00427 
00428         // XXX less, than greater than don't make sense,
00429         // should check for those bad conditions
00430 
00431         gm = QOF_GUID_MATCH_ANY;
00432         if (QOF_COMPARE_NEQ == qop)
00433             gm = QOF_GUID_MATCH_NONE;
00434         guid_list = g_list_append (NULL, &guid);
00435         pred_data = qof_query_guid_predicate (gm, guid_list);
00436 
00437         g_list_free (guid_list);
00438     }
00439     else if (!strcmp (param_type, QOF_TYPE_KVP))
00440     {
00441         /* We are expecting an encoded value that looks like
00442          * /some/path/string:value
00443          */
00444         sep = strchr (qvalue_name, ':');
00445         if (!sep)
00446             return NULL;
00447         *sep = 0;
00448         path = qvalue_name;
00449         str = sep + 1;
00450         /* If str has only digits, we know its a plain number.
00451          * If its numbers and a decimal point, assume a float
00452          * If its numbers and a slash, assume numeric
00453          * If its 32 bytes of hex, assume GUID
00454          * If it looks like an iso date ... 
00455          * else assume its a string.
00456          */
00457         kval = NULL;
00458         len = strlen (str);
00459         if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
00460         {
00461             GUID guid;
00462             string_to_guid (str, &guid);
00463             kval = kvp_value_new_guid (&guid);
00464         }
00465         else if (len == strspn (str, "0123456789"))
00466         {
00467             kval = kvp_value_new_gint64 (atoll (str));
00468         }
00469         else if ((p = strchr (str, '.')) &&
00470             ((len - 1) == (strspn (str, "0123456789") +
00471                     strspn (p + 1, "0123456789"))))
00472         {
00473             kval = kvp_value_new_double (atof (str));
00474         }
00475 
00476         else if ((p = strchr (str, '/')) &&
00477             ((len - 1) == (strspn (str, "0123456789") +
00478                     strspn (p + 1, "0123456789"))))
00479         {
00480             QofNumeric num;
00481             qof_numeric_from_string (str, &num);
00482             kval = kvp_value_new_numeric (num);
00483         }
00484         else if ((p = strchr (str, '-')) &&
00485             (p = strchr (p + 1, '-')) &&
00486             (p = strchr (p + 1, ' ')) &&
00487             (p = strchr (p + 1, ':')) && (p = strchr (p + 1, ':')))
00488         {
00489             QofDate *qd;
00490             QofTime *qt;
00491 
00492             qd = qof_date_parse (str, QOF_DATE_FORMAT_UTC);
00493             qt = qof_date_to_qtime (qd);
00494             kval =
00495                 kvp_value_new_time (qt);
00496             qof_date_free (qd);
00497         }
00498 
00499         /* The default handler is a string */
00500         if (NULL == kval)
00501         {
00502             kval = kvp_value_new_string (str);
00503         }
00504         pred_data = qof_query_kvp_predicate_path (qop, path, kval);
00505     }
00506     else
00507     {
00508         PWARN ("The predicate type \"%s\" is unsupported for now",
00509             param_type);
00510         return NULL;
00511     }
00512 
00513     qq = qof_query_create ();
00514     qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
00515     return qq;
00516 }
00517 
00518 /* ========================================================== */
00519 
00520 static QofQuery *
00521 handle_where (QofSqlQuery * query, sql_where * swear)
00522 {
00523     QofQueryOp qop;
00524     QofQuery *qq;
00525 
00526     switch (swear->type)
00527     {
00528     case SQL_pair:
00529         {
00530             QofQuery *qleft = handle_where (query, swear->d.pair.left);
00531             QofQuery *qright = handle_where (query, swear->d.pair.right);
00532             if (NULL == qleft)
00533                 return qright;
00534             if (NULL == qright)
00535                 return qleft;
00536             switch (swear->d.pair.op)
00537             {
00538             case SQL_and:
00539                 qop = QOF_QUERY_AND;
00540                 break;
00541             case SQL_or:
00542                 qop = QOF_QUERY_OR;
00543                 break;
00544                 /* XXX should add support for nand, nor, xor */
00545             default:
00546                 qof_query_destroy (qleft);
00547                 qof_query_destroy (qright);
00548                 return NULL;
00549             }
00550             qq = qof_query_merge (qleft, qright, qop);
00551             qof_query_destroy (qleft);
00552             qof_query_destroy (qright);
00553             return qq;
00554         }
00555     case SQL_negated:
00556         {
00557             QofQuery *qq = handle_where (query, swear->d.negated);
00558             QofQuery *qneg = qof_query_invert (qq);
00559             qof_query_destroy (qq);
00560             return qneg;
00561         }
00562 
00563     case SQL_single:
00564         {
00565             sql_condition *cond = swear->d.single;
00566             return handle_single_condition (query, cond);
00567         }
00568     }
00569     return NULL;
00570 }
00571 
00572 /* ========================================================== */
00573 
00574 static void
00575 handle_sort_order (QofSqlQuery * query, GList * sorder_list)
00576 {
00577     GSList *qsp[3];
00578     GList *n;
00579     gboolean direction[3];
00580     int i;
00581     sql_order_field *sorder;
00582     char *qparam_name;
00583 
00584     if (!sorder_list)
00585         return;
00586 
00587     for (i = 0; i < 3; i++)
00588     {
00589         qsp[i] = NULL;
00590         direction[i] = 0;
00591 
00592         if (sorder_list)
00593         {
00594             sorder = sorder_list->data;
00595 
00596             /* Set the sort direction */
00597             if (SQL_asc == sorder->order_type)
00598                 direction[i] = TRUE;
00599 
00600             /* Find the parameter name */
00601             qparam_name = NULL;
00602             n = sorder->name;
00603             if (n)
00604             {
00605                 qparam_name = n->data;
00606                 if (qparam_name)
00607                 {
00608                     qsp[i] =
00609                         qof_query_build_param_list (qparam_name, NULL);
00610                 }
00611                 n = n->next;    /* next parameter */
00612             }
00613             else
00614             {
00615                 /* if no next parameter, then next order-by */
00616                 sorder_list = sorder_list->next;
00617             }
00618         }
00619     }
00620 
00621     qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
00622     qof_query_set_sort_increasing (query->qof_query, direction[0],
00623         direction[1], direction[2]);
00624 }
00625 
00626 /* INSERT INTO handlers =================================================== */
00627 
00628 static void
00629 qof_sql_insertCB (const QofParam * param, const gchar * insert_string,
00630     QofSqlQuery * query)
00631 {
00632     QofIdTypeConst type;
00633     sql_insert_statement *sis;
00634     gboolean registered_type;
00635     QofEntity *ent;
00636     /* cm_ prefix used for variables that hold the data to commit */
00637     QofNumeric cm_numeric;
00638     gdouble cm_double;
00639     gboolean cm_boolean;
00640     gint32 cm_i32;
00641     gint64 cm_i64;
00642     gchar cm_char, *tail;
00643     GUID *cm_guid;
00644 /*  KvpFrame       *cm_kvp;
00645     KvpValue       *cm_value;
00646     KvpValueType   cm_type;*/
00647     void (*string_setter) (QofEntity *, const gchar *);
00648     void (*time_setter) (QofEntity *, QofTime *);
00649     void (*numeric_setter) (QofEntity *, QofNumeric);
00650     void (*double_setter) (QofEntity *, gdouble);
00651     void (*boolean_setter) (QofEntity *, gboolean);
00652     void (*i32_setter) (QofEntity *, gint32);
00653     void (*i64_setter) (QofEntity *, gint64);
00654     void (*char_setter) (QofEntity *, gchar);
00655 /*  void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/
00656 
00657     g_return_if_fail (param || insert_string || query);
00658     ent = query->inserted_entity;
00659     sis = query->parse_result->statement;
00660     type = g_strdup_printf ("%s", sis->table->d.simple);
00661 
00662     ENTER (" param=%s param_type=%s type=%s content=%s",
00663         param->param_name, param->param_type, type, insert_string);
00664     if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0)
00665     {
00666         string_setter =
00667             (void (*)(QofEntity *, const char *)) param->param_setfcn;
00668         if (string_setter != NULL)
00669         {
00670             string_setter (ent, insert_string);
00671         }
00672         registered_type = TRUE;
00673     }
00674     if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0)
00675     {
00676         QofDate *qd;
00677         QofTime *qt;
00678         time_setter = 
00679             (void (*)(QofEntity *, QofTime *)) param->param_setfcn;
00680         qd = qof_date_parse (insert_string, QOF_DATE_FORMAT_UTC);
00681         qt = qof_date_to_qtime (qd);
00682         if((time_setter != NULL) && (qof_time_is_valid(qt)))
00683         {
00684             time_setter (ent, qt);
00685         }
00686     }
00687 #ifndef QOF_DISABLE_DEPRECATED
00688     if (safe_strcmp (param->param_type, QOF_TYPE_DATE) == 0)
00689     {
00690         void (*date_setter) (QofEntity *, Timespec);
00691         Timespec cm_date;
00692         struct tm query_time;
00693         time_t query_time_t;
00694 
00695         date_setter =
00696             (void (*)(QofEntity *, Timespec)) param->param_setfcn;
00697         strptime (insert_string, QOF_UTC_DATE_FORMAT, &query_time);
00698         query_time_t = mktime (&query_time);
00699         timespecFromTime_t (&cm_date, query_time_t);
00700         if (date_setter != NULL)
00701         {
00702             date_setter (ent, cm_date);
00703         }
00704     }
00705 #endif
00706     if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) ||
00707         (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0))
00708     {
00709         numeric_setter =
00710             (void (*)(QofEntity *, QofNumeric)) param->param_setfcn;
00711         qof_numeric_from_string (insert_string, &cm_numeric);
00712         if (numeric_setter != NULL)
00713         {
00714             numeric_setter (ent, cm_numeric);
00715         }
00716     }
00717     if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0)
00718     {
00719         cm_guid = g_new (GUID, 1);
00720         if (TRUE != string_to_guid (insert_string, cm_guid))
00721         {
00722             LEAVE (" string to guid failed for %s", insert_string);
00723             return;
00724         }
00725 /*          reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
00726         if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type)) 
00727         {
00728             qof_entity_set_guid(qsf_ent, cm_guid);
00729         }
00730         else {
00731             reference = qof_entity_get_reference_from(qsf_ent, cm_param);
00732             if(reference) {
00733                 params->referenceList = g_list_append(params->referenceList, reference);
00734             }
00735         }*/
00736     }
00737     if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0)
00738     {
00739         errno = 0;
00740         cm_i32 = (gint32) strtol (insert_string, &tail, 0);
00741         if (errno == 0)
00742         {
00743             i32_setter =
00744                 (void (*)(QofEntity *, gint32)) param->param_setfcn;
00745             if (i32_setter != NULL)
00746             {
00747                 i32_setter (ent, cm_i32);
00748             }
00749         }
00750         else
00751         {
00752             QofBackend *backend;
00753             QofBook *book;
00754 
00755             book = qof_instance_get_book ((QofInstance *) ent);
00756             backend = qof_book_get_backend (book);
00757             qof_error_set_be (backend, qof_error_register 
00758             (_("When converting SQLite strings into numbers, an "
00759             "overflow has been detected. The SQLite database "
00760             "'%s' contains invalid data in a field that is meant "
00761             "to hold a number."), TRUE));
00762         }
00763     }
00764     if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0)
00765     {
00766         errno = 0;
00767         cm_i64 = strtoll (insert_string, &tail, 0);
00768         if (errno == 0)
00769         {
00770             i64_setter =
00771                 (void (*)(QofEntity *, gint64)) param->param_setfcn;
00772             if (i64_setter != NULL)
00773             {
00774                 i64_setter (ent, cm_i64);
00775             }
00776         }
00777         else
00778         {
00779             QofBackend *backend;
00780             QofBook *book;
00781 
00782             book = qof_instance_get_book ((QofInstance *) ent);
00783             backend = qof_book_get_backend (book);
00784             qof_error_set_be (backend, qof_error_register 
00785             (_("When converting SQLite strings into numbers, an "
00786             "overflow has been detected. The SQLite database "
00787             "'%s' contains invalid data in a field that is meant "
00788             "to hold a number."), TRUE));
00789         }
00790     }
00791     if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0)
00792     {
00793         errno = 0;
00794         cm_double = strtod (insert_string, &tail);
00795         if (errno == 0)
00796         {
00797             double_setter =
00798                 (void (*)(QofEntity *, double)) param->param_setfcn;
00799             if (double_setter != NULL)
00800             {
00801                 double_setter (ent, cm_double);
00802             }
00803         }
00804     }
00805     if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0)
00806     {
00807         gint b;
00808         b = qof_util_bool_to_int (insert_string);
00809         if (b == 1)
00810         {
00811             cm_boolean = TRUE;
00812         }
00813         else
00814         {
00815             cm_boolean = FALSE;
00816         }
00817         boolean_setter =
00818             (void (*)(QofEntity *, gboolean)) param->param_setfcn;
00819         if (boolean_setter != NULL)
00820         {
00821             boolean_setter (ent, cm_boolean);
00822         }
00823     }
00824     if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0)
00825     {
00826 
00827     }
00828     if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0)
00829     {
00830         cm_char = *insert_string;
00831         char_setter = (void (*)(QofEntity *, char)) param->param_setfcn;
00832         if (char_setter != NULL)
00833         {
00834             char_setter (ent, cm_char);
00835         }
00836     }
00837     LEAVE (" ");
00838 }
00839 
00840 static void
00841 qof_query_set_insert_table (QofSqlQuery * query)
00842 {
00843     sql_insert_statement *sis;
00844     sql_table *sis_t;
00845     sis = query->parse_result->statement;
00846     switch (sis->table->type)
00847     {
00848     case SQL_simple:
00849         {
00850             sis_t = sis->table;
00851             query->single_global_tablename =
00852                 g_strdup_printf ("%s", sis_t->d.simple);
00853             qof_query_search_for (query->qof_query,
00854                 query->single_global_tablename);
00855             PINFO (" insert set to table: %s", sis_t->d.simple);
00856             break;
00857         }
00858     default:
00859         {
00860             PWARN ("SQL insert only handles simple statements");
00861         }
00862     }
00863 }
00864 
00865 static QofEntity *
00866 qof_query_insert (QofSqlQuery * query)
00867 {
00868     GList *field_list, *value_list, *cur;
00869     const gchar *param_name;
00870     gchar *value;
00871     QofIdType type;
00872     const QofParam *param;
00873     QofInstance *inst;
00874     sql_insert_statement *sis;
00875     sql_field *field;
00876     sql_field_item *item;
00877 
00878     ENTER (" ");
00879     query->param_list = NULL;
00880     type = NULL;
00881     param = NULL;
00882     value = NULL;
00883     field_list = NULL;
00884     value_list = NULL;
00885     param_name = NULL;
00886     sis = query->parse_result->statement;
00887     if (!sis->fields || !sis->values)
00888     {
00889         LEAVE (" NULL insert statement");
00890         return NULL;
00891     }
00892     type = g_strdup (query->single_global_tablename);
00893     inst = (QofInstance *) qof_object_new_instance (type, query->book);
00894     if (inst == NULL)
00895     {
00896         LEAVE (" unable to create instance of type %s", type);
00897         return NULL;
00898     }
00899     query->inserted_entity = &inst->entity;
00900     value_list = sis->values;
00901     for (field_list = sis->fields; field_list != NULL;
00902         field_list = field_list->next)
00903     {
00904         field = value_list->data;
00905         item = field->item;
00906         for (cur = item->d.name; cur != NULL; cur = cur->next)
00907         {
00908             value =
00909                 g_strdup_printf ("%s",
00910                 dequote_string ((char *) cur->data));
00911         }
00912         field = field_list->data;
00913         item = field->item;
00914         for (cur = item->d.name; cur != NULL; cur = cur->next)
00915         {
00916             param_name = g_strdup_printf ("%s", (char *) cur->data);
00917             param = qof_class_get_parameter (type, param_name);
00918         }
00919         if (param && value)
00920         {
00921             qof_sql_insertCB (param, value, query);
00922         }
00923         value_list = g_list_next (value_list);
00924     }
00925     LEAVE (" ");
00926     return query->inserted_entity;
00927 }
00928 
00929 static const char *
00930 sql_type_as_string (sql_statement_type type)
00931 {
00932     switch (type)
00933     {
00934     case SQL_select:
00935         {
00936             return "SELECT";
00937         }
00938     case SQL_insert:
00939         {
00940             return "INSERT";
00941         }
00942     case SQL_delete:
00943         {
00944             return "DELETE";
00945         }
00946     case SQL_update:
00947         {
00948             return "UPDATE";
00949         }
00950     default:
00951         {
00952             return "unknown";
00953         }
00954     }
00955 }
00956 
00957 void
00958 qof_sql_query_parse (QofSqlQuery * query, const char *str)
00959 {
00960     GList *tables;
00961     char *buf;
00962     sql_select_statement *sss;
00963     sql_where *swear;
00964 
00965     if (!query)
00966         return;
00967     ENTER (" ");
00968     /* Delete old query, if any */
00969     if (query->qof_query)
00970     {
00971         qof_query_destroy (query->qof_query);
00972         sql_destroy (query->parse_result);
00973         query->qof_query = NULL;
00974     }
00975 
00976     /* Parse the SQL string */
00977     buf = g_strdup (str);
00978     query->parse_result = sql_parse (buf);
00979     g_free (buf);
00980 
00981     if (!query->parse_result)
00982     {
00983         LEAVE ("parse error");
00984         return;
00985     }
00986 
00987     if ((SQL_select != query->parse_result->type)
00988         && (SQL_insert != query->parse_result->type))
00989     {
00990         LEAVE
00991             ("currently, only SELECT or INSERT statements are supported, "
00992             "got type=%s", sql_type_as_string (query->parse_result->type));
00993         return;
00994     }
00995 
00996     /* If the user wrote "SELECT * FROM tablename WHERE ..."
00997      * then we have a single global tablename.  But if the 
00998      * user wrote "SELECT * FROM tableA, tableB WHERE ..."
00999      * then we don't have a single unique table-name.
01000      */
01001     tables = sql_statement_get_tables (query->parse_result);
01002     if (1 == g_list_length (tables))
01003     {
01004         query->single_global_tablename = tables->data;
01005     }
01006     /* if this is an insert, we're done with the parse. */
01007     if (SQL_insert == query->parse_result->type)
01008     {
01009         query->qof_query = qof_query_create ();
01010         qof_query_set_insert_table (query);
01011         LEAVE (" insert statement parsed OK");
01012         return;
01013     }
01014     sss = query->parse_result->statement;
01015     swear = sss->where;
01016     if (swear)
01017     {
01018         /* Walk over the where terms, turn them into QOF predicates */
01019         query->qof_query = handle_where (query, swear);
01020         if (NULL == query->qof_query)
01021         {
01022             LEAVE (" no query found");
01023             return;
01024         }
01025     }
01026     else
01027     {
01028         query->qof_query = qof_query_create ();
01029     }
01030     /* Provide support for different sort orders */
01031     handle_sort_order (query, sss->order);
01032 
01033     /* We also want to set the type of thing to search for.
01034      * SELECT * FROM table1, table2, ... is not supported.
01035      * Use sequential queries and build a partial book.
01036      */
01037     qof_query_search_for (query->qof_query,
01038         query->single_global_tablename);
01039     LEAVE (" success");
01040 }
01041 
01042 /* ========================================================== */
01043 
01044 GList *
01045 qof_sql_query_run (QofSqlQuery * query, const char *str)
01046 {
01047     GList *results;
01048 
01049     if (!query)
01050         return NULL;
01051 
01052     qof_sql_query_parse (query, str);
01053     if (NULL == query->qof_query)
01054     {
01055         PINFO (" Null query");
01056         return NULL;
01057     }
01058 
01059     qof_query_set_book (query->qof_query, query->book);
01060     /* Maybe log this sucker */
01061     if (qof_log_check (log_module, QOF_LOG_DETAIL))
01062     {
01063         qof_query_print (query->qof_query);
01064     }
01065     if (SQL_insert == query->parse_result->type)
01066     {
01067         results = NULL;
01068         results = g_list_append (results, qof_query_insert (query));
01069         return results;
01070     }
01071 
01072     results = qof_query_run (query->qof_query);
01073 
01074     return results;
01075 }
01076 
01077 GList *
01078 qof_sql_query_rerun (QofSqlQuery * query)
01079 {
01080     GList *results;
01081 
01082     if (!query)
01083         return NULL;
01084 
01085     if (NULL == query->qof_query)
01086         return NULL;
01087 
01088     qof_query_set_book (query->qof_query, query->book);
01089 
01090     /* Maybe log this sucker */
01091     if (qof_log_check (log_module, QOF_LOG_DETAIL))
01092     {
01093         qof_query_print (query->qof_query);
01094     }
01095 
01096     results = qof_query_run (query->qof_query);
01097 
01098     return results;
01099 }
01100 
01101 /* ========================== END OF FILE =================== */

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4