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  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00019  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
00020  *                                                                  *
00021 \********************************************************************/
00022 
00029 #define _GNU_SOURCE
00030 
00031 #include <stdlib.h>   /* for working atoll */
00032 #include <errno.h>
00033 #include "glib.h"
00034 #include "config.h"
00035 #ifdef HAVE_GDA
00036 #include <sql/sql_parser.h>
00037 #else
00038 #include "sql_parser.h"
00039 #endif
00040 #include <time.h>
00041 #include "kvp_frame.h"
00042 #include "gnc-date.h"
00043 #include "gnc-numeric.h"
00044 #include "gnc-trace.h"
00045 #include "guid.h"
00046 #include "qofbook.h"
00047 #include "qofquery.h"
00048 #include "qofquerycore.h"
00049 #include "qofsql.h"
00050 #include "gnc-engine-util.h"
00051 #include "qofinstance-p.h"
00052 #include "qofobject.h"
00053 
00054 static QofLogModule log_module = QOF_MOD_QUERY;
00055 
00056 /* =================================================================== */
00057 
00058 struct _QofSqlQuery
00059 {
00060         sql_statement *parse_result;
00061         QofQuery *qof_query;
00062         QofBook *book;
00063         char * single_global_tablename;
00064         KvpFrame *kvp_join;
00065         GList *param_list;
00066         QofEntity *inserted_entity;
00067 };
00068 
00069 /* ========================================================== */
00070 
00071 QofSqlQuery *
00072 qof_sql_query_new(void)
00073 {
00074         QofSqlQuery * sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
00075         
00076         sqn->qof_query = NULL;
00077         sqn->parse_result = NULL;
00078         sqn->book = NULL;
00079         sqn->single_global_tablename = NULL;
00080         sqn->kvp_join = NULL;
00081 
00082         return sqn;
00083 }
00084 
00085 /* ========================================================== */
00086 
00087 void 
00088 qof_sql_query_destroy (QofSqlQuery *q)
00089 {
00090         if (!q) return;
00091         qof_query_destroy (q->qof_query);
00092         sql_destroy (q->parse_result);
00093         g_free (q);
00094 }
00095 
00096 /* ========================================================== */
00097 
00098 QofQuery * 
00099 qof_sql_query_get_query (QofSqlQuery *q)
00100 {
00101         if (!q) return NULL;
00102         return q->qof_query;
00103 }
00104 
00105 /* ========================================================== */
00106 
00107 void 
00108 qof_sql_query_set_book (QofSqlQuery *q, QofBook *book)
00109 {
00110         if (!q) return;
00111         q->book = book;
00112 }
00113 
00114 /* ========================================================== */
00115 
00116 void 
00117 qof_sql_query_set_kvp (QofSqlQuery *q, KvpFrame *kvp)
00118 {
00119         if (!q) return;
00120         q->kvp_join = kvp;
00121 }
00122 
00123 /* ========================================================== */
00124 
00125 static inline void
00126 get_table_and_param (char * str, char **tab, char **param)
00127 {
00128         char * end = strchr (str, '.');
00129         if (!end) 
00130         {
00131                 *tab = 0;
00132                 *param = str;
00133                 return;
00134         }
00135         *end = 0;
00136         *tab = str;
00137         *param = end+1;
00138 }
00139 
00140 static inline char * 
00141 dequote_string (char *str)
00142 {
00143         size_t len;
00144         /* strip out quotation marks ...  */
00145         if (('\'' == str[0]) ||
00146             ('\"' == str[0]))
00147         {
00148                 str ++;
00149                 len = strlen(str);
00150                 str[len-1] = 0;
00151         }
00152         return str;
00153 }
00154 
00155 static QofQuery *
00156 handle_single_condition (QofSqlQuery *query, sql_condition * cond)
00157 {
00158         char tmpbuff[128];
00159         GSList *param_list;
00160         GList *guid_list;
00161         QofQueryPredData *pred_data;
00162         sql_field_item *sparam, *svalue;
00163         char * qparam_name, *qvalue_name, *table_name, *param_name;
00164         char *sep, *path,*str,*p;
00165         QofQuery *qq;
00166         KvpValue *kv, *kval;
00167         KvpValueType kvt;
00168         QofQueryCompare qop;
00169         time_t exact;
00170         int rc, len;
00171         Timespec ts;
00172         QofType param_type;
00173         QofGuidMatch gm;
00174         
00175         pred_data = NULL;
00176         if (NULL == cond)
00177         {
00178                 PWARN("missing condition");
00179                 return NULL;
00180         }
00181         /* -------------------------------- */
00182         /* field to match, assumed, for now to be on the left */
00183         /* XXX fix this so it can be either left or right */
00184         if (NULL == cond->d.pair.left)
00185         {
00186                 PWARN("missing left parameter");
00187                 return NULL;
00188         }
00189         sparam = cond->d.pair.left->item;
00190         if (SQL_name != sparam->type)
00191         {
00192                 PWARN("we support only parameter names at this time (parsed %d)",
00193           sparam->type);
00194                 return NULL;
00195         }
00196         qparam_name = sparam->d.name->data;
00197         if (NULL == qparam_name)
00198         {
00199                 PWARN ("missing parameter name");
00200                 return NULL;
00201         }
00202 
00203         /* -------------------------------- */
00204         /* value to match, assumed, for now, to be on the right. */
00205         /* XXX fix this so it can be either left or right */
00206         if (NULL == cond->d.pair.right)
00207         {
00208                 PWARN ("missing right parameter");
00209                 return NULL;
00210         }
00211         svalue = cond->d.pair.right->item;
00212         if (SQL_name != svalue->type)
00213         {
00214                 PWARN("we support only simple values (parsed as %d)", svalue->type);
00215                 return NULL;
00216         }
00217         qvalue_name = svalue->d.name->data;
00218         if (NULL == qvalue_name)
00219         {
00220                 PWARN("missing value");
00221                 return NULL;
00222         }
00223         qvalue_name = dequote_string (qvalue_name);
00224         qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
00225 
00226         /* Look to see if its the special KVP value holder.
00227          * If it is, look up the value. */
00228         if (0 == strncasecmp (qvalue_name, "kvp://", 6))
00229         {
00230                 if (NULL == query->kvp_join)
00231                 {
00232                         PWARN ("missing kvp frame");
00233                         return NULL;
00234                 }
00235                 kv = kvp_frame_get_value (query->kvp_join, qvalue_name+5);
00236                 /* If there's no value, its not an error; 
00237                  * we just don't do this predicate */
00238                 if (!kv) return NULL;  
00239                 kvt = kvp_value_get_type (kv);
00240 
00241                 tmpbuff[0] = 0x0;
00242                 qvalue_name = tmpbuff;
00243                 switch (kvt)
00244                 {
00245                         case KVP_TYPE_GINT64:
00246                         {
00247                                 gint64 ival = kvp_value_get_gint64(kv);
00248                                 sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival);
00249                                 break;
00250                         }
00251                         case KVP_TYPE_DOUBLE:
00252                         {
00253                                 double ival = kvp_value_get_double(kv);
00254                                 sprintf (tmpbuff, "%26.18g\n", ival);
00255                                 break;
00256                         }
00257                         case KVP_TYPE_STRING:
00258                                 /* If there's no value, its not an error; 
00259                                  * we just don't do this predicate */
00260                                 qvalue_name = kvp_value_get_string (kv);
00261                                 if (!qvalue_name) return NULL;
00262                                 break;
00263                         case KVP_TYPE_GUID:
00264                         case KVP_TYPE_TIMESPEC:
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:    qop = QOF_COMPARE_EQUAL; break;
00282                 case SQL_gt:    qop = QOF_COMPARE_GT; break;
00283                 case SQL_lt:    qop = QOF_COMPARE_LT; break;
00284                 case SQL_geq:   qop = QOF_COMPARE_GTE; break;
00285                 case SQL_leq:   qop = QOF_COMPARE_LTE; break;
00286                 case SQL_diff:  qop = QOF_COMPARE_NEQ; break;
00287                 default:
00288                         /* XXX for string-type queries, we should be able to
00289                          * support 'IN' for substring search.  Also regex. */
00290                         PWARN ("Unsupported compare op (parsed as %u)", cond->op);
00291                         return NULL;
00292         }
00293 
00294         /* OK, need to know the type of the thing being matched 
00295          * in order to build the correct predicate.  Get the type 
00296          * from the object parameters. */
00297         get_table_and_param (qparam_name, &table_name, &param_name);
00298         if (NULL == table_name)
00299         {
00300                 table_name = query->single_global_tablename;
00301         }
00302         if (NULL == table_name)
00303         {
00304                 PWARN ("Need to specify an object class to query");
00305                 return NULL;
00306         }
00307 
00308         if (FALSE == qof_class_is_registered (table_name)) 
00309         {
00310                 PWARN ("The query object \'%s\' is not known", table_name);
00311                 return NULL;
00312         }
00313 
00314         param_type = qof_class_get_parameter_type (table_name, param_name);
00315         if (!param_type) 
00316         {
00317                 PWARN ("The parameter \'%s\' on object \'%s\' is not known", 
00318                        param_name, table_name);
00319                 return NULL;
00320         }
00321 
00322         if (!strcmp (param_type, QOF_TYPE_STRING))
00323         {
00324                 pred_data = 
00325                     qof_query_string_predicate (qop,        /* comparison to make */
00326                           qvalue_name,                      /* string to match */
00327                           QOF_STRING_MATCH_CASEINSENSITIVE,  /* case matching */
00328                           FALSE);                            /* use_regexp */
00329         }
00330         else if (!strcmp (param_type, QOF_TYPE_CHAR))
00331         {
00332                 QofCharMatch cm = QOF_CHAR_MATCH_ANY;
00333                 if (QOF_COMPARE_NEQ == qop) cm = QOF_CHAR_MATCH_NONE;
00334                 pred_data = qof_query_char_predicate (cm, qvalue_name);
00335         }
00336         else if (!strcmp (param_type, QOF_TYPE_INT32))
00337         {
00338                 gint32 ival = atoi (qvalue_name);
00339                 pred_data = qof_query_int32_predicate (qop, ival);
00340         }
00341         else if (!strcmp (param_type, QOF_TYPE_INT64))
00342         {
00343                 gint64 ival = atoll (qvalue_name);
00344                 pred_data = qof_query_int64_predicate (qop, ival);
00345         }
00346         else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
00347         {
00348                 double ival = atof (qvalue_name);
00349                 pred_data = qof_query_double_predicate (qop, ival);
00350         }
00351         else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
00352         {
00353                 gboolean ival = qof_util_bool_to_int (qvalue_name);
00354                 pred_data = qof_query_boolean_predicate (qop, ival);
00355         }
00356         else if (!strcmp (param_type, QOF_TYPE_DATE))
00357         {
00358                 /* Use a timezone independent setting */
00359                 qof_date_format_set(QOF_DATE_FORMAT_UTC);
00360                 rc = 0;
00361                 if(FALSE == qof_scan_date_secs (qvalue_name, &exact))
00362                 {
00363                         char *tail;
00364                         exact = strtoll(qvalue_name, &tail, 0);
00365 //                      PWARN ("unable to parse date: %s", qvalue_name);
00366 //                      return NULL;
00367                 }
00368                 ts.tv_sec = exact;
00369                 ts.tv_nsec = 0;
00370                 pred_data = qof_query_date_predicate (qop, QOF_DATE_MATCH_NORMAL, ts);
00371         }
00372         else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
00373         {
00374                 gnc_numeric ival;
00375                 string_to_gnc_numeric (qvalue_name, &ival);
00376                 pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
00377         }
00378         else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
00379         {
00380                 // XXX this probably needs some work ... 
00381                 gnc_numeric ival;
00382                 string_to_gnc_numeric (qvalue_name, &ival);
00383                 pred_data = qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
00384         }
00385         else if (!strcmp (param_type, QOF_TYPE_GUID))
00386         {
00387                 GUID guid;
00388                 gboolean rc = string_to_guid (qvalue_name, &guid);
00389                 if (0 == rc)
00390                 {
00391                         PWARN ("unable to parse guid: %s", qvalue_name);
00392                         return NULL;
00393                 }
00394 
00395                 // XXX less, than greater than don't make sense,
00396                 // should check for those bad conditions
00397 
00398                 gm = QOF_GUID_MATCH_ANY;
00399                 if (QOF_COMPARE_NEQ == qop) gm = QOF_GUID_MATCH_NONE;
00400                 guid_list = g_list_append (NULL, &guid);
00401                 pred_data = qof_query_guid_predicate (gm, guid_list);
00402 
00403                 g_list_free (guid_list);
00404         }
00405         else if (!strcmp (param_type, QOF_TYPE_KVP))
00406         {
00407                 /* We are expecting an encoded value that looks like
00408                  * /some/path/string:value
00409                  */
00410                 sep = strchr (qvalue_name, ':');
00411                 if (!sep) return NULL;
00412                 *sep = 0;
00413                 path = qvalue_name;
00414                 str = sep +1;
00415                 /* If str has only digits, we know its a plain number.
00416                  * If its numbers and a decimal point, assume a float
00417                  * If its numbers and a slash, assume numeric
00418                  * If its 32 bytes of hex, assume GUID
00419                  * If it looks like an iso date ... 
00420                  * else assume its a string.
00421                  */
00422                 kval = NULL;
00423                 len = strlen (str);
00424                 if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
00425                 {
00426                         GUID guid;
00427                         string_to_guid (str, &guid);
00428                         kval = kvp_value_new_guid (&guid);
00429                 }
00430                 else
00431                 if (len == strspn (str, "0123456789"))
00432                 {
00433                         kval = kvp_value_new_gint64 (atoll(str));
00434                 }
00435                 else
00436                 if ((p=strchr (str, '.')) && 
00437                     ((len-1) == (strspn (str, "0123456789") + 
00438                                  strspn (p+1, "0123456789"))))
00439                 {
00440                         kval = kvp_value_new_double (atof(str));
00441                 }
00442 
00443                 else
00444                 if ((p=strchr (str, '/')) && 
00445                     ((len-1) == (strspn (str, "0123456789") + 
00446                                  strspn (p+1, "0123456789"))))
00447                 {
00448                         gnc_numeric num;
00449                         string_to_gnc_numeric (str, &num);
00450                         kval = kvp_value_new_gnc_numeric (num);
00451                 }
00452                 else
00453                 if ((p=strchr (str, '-')) && 
00454                     (p=strchr (p+1, '-')) && 
00455                     (p=strchr (p+1, ' ')) && 
00456                     (p=strchr (p+1, ':')) && 
00457                     (p=strchr (p+1, ':')))
00458                 {
00459                         kval = kvp_value_new_timespec (gnc_iso8601_to_timespec_gmt(str));
00460                 }
00461 
00462                 /* The default handler is a string */
00463                 if (NULL == kval)
00464                 {
00465                         kval = kvp_value_new_string (str);
00466                 }
00467                 pred_data = qof_query_kvp_predicate_path (qop, path, kval);
00468         }
00469         else
00470         {
00471                 PWARN ("The predicate type \"%s\" is unsupported for now", param_type);
00472                 return NULL;
00473         }
00474 
00475         qq = qof_query_create();
00476         qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
00477         return qq;
00478 }
00479 
00480 /* ========================================================== */
00481 
00482 static QofQuery *
00483 handle_where (QofSqlQuery *query, sql_where *swear)
00484 {
00485         QofQueryOp qop;
00486         QofQuery * qq;
00487         
00488         switch (swear->type)
00489         {
00490                 case SQL_pair:
00491                 {
00492                         QofQuery *qleft = handle_where (query, swear->d.pair.left);
00493                         QofQuery *qright = handle_where (query, swear->d.pair.right);
00494                         if (NULL == qleft) return qright;
00495                         if (NULL == qright) return qleft;
00496                         switch (swear->d.pair.op)
00497                         {
00498                                 case SQL_and: qop = QOF_QUERY_AND; break;
00499                                 case SQL_or: qop = QOF_QUERY_OR; break;
00500                                 /* XXX should add support for nand, nor, xor */
00501                                 default: 
00502                                         qof_query_destroy (qleft);
00503                                         qof_query_destroy (qright);
00504                                         return NULL;
00505                         }
00506                         qq = qof_query_merge (qleft, qright, qop);
00507                         qof_query_destroy (qleft);
00508                         qof_query_destroy (qright);
00509                         return qq;
00510                 }
00511                 case SQL_negated:
00512                 {
00513                         QofQuery *qq = handle_where (query, swear->d.negated);
00514                         QofQuery *qneg = qof_query_invert (qq);
00515                         qof_query_destroy (qq);
00516                         return qneg;
00517                 }
00518 
00519                 case SQL_single:
00520                 {
00521                         sql_condition * cond = swear->d.single;
00522                         return handle_single_condition (query, cond);
00523                 }
00524         }
00525         return NULL;
00526 }
00527 
00528 /* ========================================================== */
00529 
00530 static void 
00531 handle_sort_order (QofSqlQuery *query, GList *sorder_list)
00532 {
00533         GSList *qsp[3];
00534         GList *n;
00535         gboolean direction[3];
00536         int i;
00537         sql_order_field *sorder;
00538         char * qparam_name;
00539         
00540         if (!sorder_list) return;
00541 
00542         for (i=0; i<3; i++)
00543         {
00544                 qsp[i] = NULL;
00545                 direction[i] = 0;
00546 
00547                 if (sorder_list)
00548                 {
00549                         sorder = sorder_list->data;
00550 
00551                         /* Set the sort direction */
00552                         if (SQL_asc == sorder->order_type) direction[i] = TRUE;
00553 
00554                         /* Find the parameter name */
00555                         qparam_name = NULL;
00556                         n = sorder->name;
00557                         if (n)
00558                         {
00559                                 qparam_name = n->data;
00560                                 if (qparam_name) 
00561                                 {
00562                                         qsp[i] = qof_query_build_param_list (qparam_name, NULL);
00563                                 }
00564                                 n = n->next;   /* next parameter */
00565                         }
00566                         else
00567                         {
00568                                 /* if no next parameter, then next order-by */
00569                                 sorder_list = sorder_list->next;
00570                         }
00571                 }
00572         }
00573 
00574         qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
00575         qof_query_set_sort_increasing (query->qof_query, direction[0],
00576                                     direction[1], direction[2]);
00577 }
00578 
00579 /* ========================================================== */
00580 static void
00581 qof_queryForeachParam( QofParam* param, gpointer user_data) 
00582 {
00583         QofSqlQuery *q;
00584         
00585         g_return_if_fail(user_data != NULL);
00586         q = (QofSqlQuery*)user_data;
00587         g_return_if_fail(param != NULL);
00588         if((param->param_getfcn != NULL)&&(param->param_setfcn != NULL)) {
00589                 q->param_list = g_list_append(q->param_list, param);
00590         }
00591 }
00592 
00593 static const char*
00594 qof_sql_get_value(sql_insert_statement *insert)
00595 {
00596         GList *walk, *cur;
00597         const char *insert_string;
00598         sql_field *field;
00599         sql_field_item * item;
00600 
00601         /* how to cope with multiple results? */
00602         if (insert->values == NULL) { return NULL; }
00603         insert_string = NULL;
00604         for (walk = insert->values; walk != NULL; walk = walk->next) 
00605         {
00606                 field = walk->data;
00607                 item = field->item;
00608                 for (cur = item->d.name; cur != NULL; cur = cur->next)
00609                 {
00610                         insert_string = g_strdup_printf("%s", (char*)cur->data);
00611                 }
00612         }
00613         return insert_string;
00614 }
00615 
00616 static const QofParam*
00617 qof_sql_get_param(QofIdTypeConst type, sql_insert_statement *insert)
00618 {
00619         GList *walk, *cur;
00620         const char *param_name;
00621         const QofParam *param;
00622         sql_field *field;
00623         sql_field_item *item;
00624 
00625         param = NULL;
00626         param_name = NULL;
00627         if (insert->fields == NULL) { return NULL; }
00628         for (walk = insert->fields; walk != NULL; walk = walk->next) 
00629         {
00630                 field = walk->data;
00631                 item = field->item;
00632                 for (cur = item->d.name; cur != NULL; cur = cur->next)
00633                 {
00634                         param_name = g_strdup_printf("%s", (char*)cur->data);
00635                 }
00636         }
00637         param = qof_class_get_parameter(type, param_name);
00638         return param;
00639 }
00640 
00641 static void
00642 qof_sql_insertCB( gpointer value, gpointer data)
00643 {
00644         GList *param_list;
00645         QofSqlQuery *q;
00646         QofIdTypeConst type;
00647         sql_insert_statement *sis;
00648         const char *insert_string;
00649         gboolean    registered_type;
00650         QofEntity   *ent;
00651         QofParam    *param;
00652         struct tm   query_time;
00653         time_t      query_time_t;
00654         /* cm_ prefix used for variables that hold the data to commit */
00655         gnc_numeric    cm_numeric;
00656         double         cm_double;
00657         gboolean       cm_boolean;
00658         gint32         cm_i32;
00659         gint64         cm_i64;
00660         Timespec       cm_date;
00661         char           cm_char, *tail;
00662         GUID           *cm_guid;
00663 /*      KvpFrame       *cm_kvp;
00664         KvpValue       *cm_value;
00665         KvpValueType   cm_type;*/
00666         const QofParam *cm_param;
00667         void (*string_setter)    (QofEntity*, const char*);
00668         void (*date_setter)      (QofEntity*, Timespec);
00669         void (*numeric_setter)   (QofEntity*, gnc_numeric);
00670         void (*double_setter)    (QofEntity*, double);
00671         void (*boolean_setter)   (QofEntity*, gboolean);
00672         void (*i32_setter)       (QofEntity*, gint32);
00673         void (*i64_setter)       (QofEntity*, gint64);
00674         void (*char_setter)      (QofEntity*, char);
00675 /*      void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/
00676 
00677         q = (QofSqlQuery*)data;
00678         ent = q->inserted_entity;
00679         param = (QofParam*)value;
00680         sis = q->parse_result->statement;
00681         type = g_strdup_printf("%s", sis->table->d.simple);
00682         insert_string = g_strdup(qof_sql_get_value(sis));
00683         cm_param = qof_sql_get_param(type, sis);
00684         param_list = g_list_copy(q->param_list);
00685         while(param_list != NULL) {
00686                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_STRING) == 0)  { 
00687                         string_setter = (void(*)(QofEntity*, const char*))cm_param->param_setfcn;
00688                         if(string_setter != NULL) { string_setter(ent, insert_string); }
00689                         registered_type = TRUE;
00690                 }
00691                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_DATE) == 0) { 
00692                         date_setter = (void(*)(QofEntity*, Timespec))cm_param->param_setfcn;
00693                         strptime(insert_string, QOF_UTC_DATE_FORMAT, &query_time);
00694                         query_time_t = mktime(&query_time);
00695                         timespecFromTime_t(&cm_date, query_time_t);
00696                         if(date_setter != NULL) { date_setter(ent, cm_date); }
00697                 }
00698                 if((safe_strcmp(cm_param->param_type, QOF_TYPE_NUMERIC) == 0)  ||
00699                 (safe_strcmp(cm_param->param_type, QOF_TYPE_DEBCRED) == 0)) { 
00700                         numeric_setter = (void(*)(QofEntity*, gnc_numeric))cm_param->param_setfcn;
00701                         string_to_gnc_numeric(insert_string, &cm_numeric);
00702                         if(numeric_setter != NULL) { numeric_setter(ent, cm_numeric); }
00703                 }
00704                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_GUID) == 0) { 
00705                         cm_guid = g_new(GUID, 1);
00706                         if(TRUE != string_to_guid(insert_string, cm_guid))
00707                         {
00708                                 LEAVE (" string to guid failed for %s", insert_string);
00709                                 return;
00710                         }
00711 /*                      reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
00712                         if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type)) 
00713                         {
00714                                 qof_entity_set_guid(qsf_ent, cm_guid);
00715                         }
00716                         else {
00717                                 reference = qof_entity_get_reference_from(qsf_ent, cm_param);
00718                                 if(reference) {
00719                                         params->referenceList = g_list_append(params->referenceList, reference);
00720                                 }
00721                         }*/
00722                 }
00723                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT32) == 0) { 
00724                         errno = 0;
00725                         cm_i32 = (gint32)strtol (insert_string, &tail, 0);
00726                         if(errno == 0) {
00727                                 i32_setter = (void(*)(QofEntity*, gint32))cm_param->param_setfcn;
00728                                 if(i32_setter != NULL) { i32_setter(ent, cm_i32); }
00729                         }
00730 //                      else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
00731                 }
00732                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT64) == 0) { 
00733                         errno = 0;
00734                         cm_i64 = strtoll(insert_string, &tail, 0);
00735                         if(errno == 0) {
00736                                 i64_setter = (void(*)(QofEntity*, gint64))cm_param->param_setfcn;
00737                                 if(i64_setter != NULL) { i64_setter(ent, cm_i64); }
00738                         }
00739 //                      else { qof_backend_set_error(params->be, ERR_QSF_OVERFLOW); }
00740                 }
00741                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_DOUBLE) == 0) { 
00742                         errno = 0;
00743                         cm_double = strtod(insert_string, &tail);
00744                         if(errno == 0) {
00745                                 double_setter = (void(*)(QofEntity*, double))cm_param->param_setfcn;
00746                                 if(double_setter != NULL) { double_setter(ent, cm_double); }
00747                         }
00748                 }
00749                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_BOOLEAN) == 0){ 
00750                         if(0 == safe_strcmp(insert_string, "TRUE")) {
00751                                 cm_boolean = TRUE;
00752                         }
00753                         else { cm_boolean = FALSE; }
00754                         boolean_setter = (void(*)(QofEntity*, gboolean))cm_param->param_setfcn;
00755                         if(boolean_setter != NULL) { boolean_setter(ent, cm_boolean); }
00756                 }
00757                         if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) { 
00758                                 
00759                         }
00760                 if(safe_strcmp(cm_param->param_type, QOF_TYPE_CHAR) == 0) { 
00761                         cm_char = *insert_string;
00762                         char_setter = (void(*)(QofEntity*, char))cm_param->param_setfcn;
00763                         if(char_setter != NULL) { char_setter(ent, cm_char); }
00764                 }
00765                 param_list = param_list->next;
00766         }
00767 }
00768 
00769 static QofEntity*
00770 qof_query_insert(QofSqlQuery *query)
00771 {
00772         QofIdType type;
00773         QofInstance *inst;
00774         sql_insert_statement *sis;
00775         sql_table *sis_t;
00776 
00777         query->param_list = NULL;
00778         type = NULL;
00779         sis = query->parse_result->statement;
00780         switch(sis->table->type) {
00781                 case SQL_simple: {
00782                         sis_t = sis->table;
00783                         query->single_global_tablename = g_strdup_printf("%s", sis_t->d.simple);
00784                         type = g_strdup(query->single_global_tablename);
00785                         break;
00786                 }
00787                 default: {
00788                         fprintf(stderr, "default");
00789                 }
00790         }
00791         inst = (QofInstance*)qof_object_new_instance(type, query->book);
00792         if(inst == NULL) { return NULL; }
00793         query->param_list = NULL;
00794         query->inserted_entity = &inst->entity;
00795         qof_class_param_foreach((QofIdTypeConst)type, qof_queryForeachParam, query);
00796         g_list_foreach(query->param_list, qof_sql_insertCB, query);
00797         return query->inserted_entity;
00798 }
00799 
00800 static const char*
00801 sql_type_as_string(sql_statement_type type)
00802 {
00803         switch (type)
00804         {
00805                 case SQL_select : { return "SELECT"; }
00806                 case SQL_insert : { return "INSERT"; }
00807                 case SQL_delete : { return "DELETE"; }
00808                 case SQL_update : { return "UPDATE"; }
00809                 default : { return "unknown"; }
00810         }
00811 }
00812 
00813 void 
00814 qof_sql_query_parse (QofSqlQuery *query, const char *str)
00815 {
00816         GList *tables;
00817         char *buf;
00818         sql_select_statement *sss;
00819         sql_where *swear;
00820         
00821         if (!query) return;
00822 
00823         /* Delete old query, if any */
00824         if (query->qof_query)
00825         {
00826                 qof_query_destroy (query->qof_query);
00827                 sql_destroy(query->parse_result);
00828                 query->qof_query = NULL;
00829         }
00830 
00831         /* Parse the SQL string */
00832         buf = g_strdup(str);
00833         query->parse_result = sql_parse (buf);
00834         g_free(buf);
00835 
00836         if (!query->parse_result) 
00837         {
00838                 PWARN ("parse error"); 
00839                 return;
00840         }
00841 
00842         if ((SQL_select != query->parse_result->type)&&(SQL_insert != query->parse_result->type))
00843         {
00844                 PWARN("currently, only SELECT or INSERT statements are supported, "
00845                          "got type=%s", sql_type_as_string(query->parse_result->type));
00846                 return;
00847         }
00848 
00849         /* If the user wrote "SELECT * FROM tablename WHERE ..."
00850          * then we have a single global tablename.  But if the 
00851          * user wrote "SELECT * FROM tableA, tableB WHERE ..."
00852          * then we don't have a single unique table-name.
00853          */
00854         tables = sql_statement_get_tables (query->parse_result);
00855         if (1 == g_list_length (tables))
00856         {
00857                 query->single_global_tablename = tables->data;
00858         }
00859         /* if this is an insert, we're done with the parse. */
00860         if(SQL_insert == query->parse_result->type) {
00861                 query->qof_query = qof_query_create();
00862                 return;
00863         }
00864         sss = query->parse_result->statement;
00865         swear = sss->where;
00866         if (swear)
00867         {
00868                 /* Walk over the where terms, turn them into QOF predicates */
00869                 query->qof_query = handle_where (query, swear);
00870                 if (NULL == query->qof_query) return;
00871         }
00872         else
00873         {
00874                 query->qof_query = qof_query_create();
00875         }
00876         /* Provide support for different sort orders */
00877         handle_sort_order (query, sss->order);
00878 
00879         /* We also want to set the type of thing to search for.
00880          * If the user said SELECT * FROM ... then we should return
00881          * a list of QofEntity.  Otherwise, we return ... ?
00882          * XXX all this needs fixing.
00883          */
00884         qof_query_search_for (query->qof_query, query->single_global_tablename);
00885 }
00886 
00887 /* ========================================================== */
00888 
00889 GList * 
00890 qof_sql_query_run (QofSqlQuery *query, const char *str)
00891 {
00892         GList *results;
00893         
00894         if (!query) return NULL;
00895 
00896         qof_sql_query_parse (query, str);
00897         if (NULL == query->qof_query) return NULL;
00898 
00899         qof_query_set_book (query->qof_query, query->book);
00900         if(SQL_insert == query->parse_result->type){
00901                 results = NULL;
00902                 results = g_list_append(results, qof_query_insert(query));
00903                 return results;
00904         }
00905         qof_query_print (query->qof_query);
00906         results = qof_query_run (query->qof_query);
00907 
00908         return results;
00909 }
00910 
00911 GList * 
00912 qof_sql_query_rerun (QofSqlQuery *query)
00913 {
00914         GList *results;
00915 
00916         if (!query) return NULL;
00917 
00918         if (NULL == query->qof_query) return NULL;
00919 
00920         qof_query_set_book (query->qof_query, query->book);
00921 
00922         // qof_query_print (query->qof_query);
00923         results = qof_query_run (query->qof_query);
00924 
00925         return results;
00926 }
00927 
00928 /* ========================== END OF FILE =================== */

Generated on Fri Oct 21 15:49:56 2005 for QOF by  doxygen 1.4.5