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

Generated on Fri Sep 1 15:10:40 2006 for QOF by  doxygen 1.4.7