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