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

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4