QOF
0.8.7
|
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 00034 #include "config.h" 00035 #include <stdlib.h> /* for working atoll */ 00036 #include <errno.h> 00037 #include <glib.h> 00038 #include <libintl.h> 00039 #ifdef HAVE_GDA 00040 #include <libsql/sql_parser.h> 00041 #else 00042 #include "sql_parser.h" 00043 #endif 00044 #include <time.h> 00045 #include "qof.h" 00046 #include "qofsql-p.h" 00047 #include "qofquery-p.h" 00048 00049 #define _(String) dgettext (GETTEXT_PACKAGE, String) 00050 00051 static gchar * kvp_table_name = NULL; 00052 00053 #define QSQL_KVP_TABLE "sql_kvp" 00054 00055 #define END_DB_VERSION " dbversion int );" 00056 00057 static QofLogModule log_module = QOF_MOD_QUERY; 00058 00059 /* =================================================================== */ 00060 00061 struct _QofSqlQuery 00062 { 00063 sql_statement *parse_result; 00064 QofQuery *qof_query; 00065 QofBook *book; 00066 gchar *single_global_tablename; 00067 KvpFrame *kvp_join; 00068 GList *param_list; 00069 QofEntity *inserted_entity; 00070 }; 00071 00072 /* ========================================================== */ 00073 00074 QofSqlQuery * 00075 qof_sql_query_new (void) 00076 { 00077 QofSqlQuery *sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1); 00078 00079 sqn->qof_query = NULL; 00080 sqn->parse_result = NULL; 00081 sqn->book = NULL; 00082 sqn->single_global_tablename = NULL; 00083 sqn->kvp_join = NULL; 00084 00085 return sqn; 00086 } 00087 00088 /* ========================================================== */ 00089 00090 void 00091 qof_sql_query_destroy (QofSqlQuery * q) 00092 { 00093 if (!q) 00094 return; 00095 qof_query_destroy (q->qof_query); 00096 sql_destroy (q->parse_result); 00097 g_free (q); 00098 } 00099 00100 /* ========================================================== */ 00101 00102 QofQuery * 00103 qof_sql_query_get_query (QofSqlQuery * q) 00104 { 00105 if (!q) 00106 return NULL; 00107 return q->qof_query; 00108 } 00109 00110 /* ========================================================== */ 00111 00112 void 00113 qof_sql_query_set_book (QofSqlQuery * q, QofBook * book) 00114 { 00115 if (!q) 00116 return; 00117 q->book = book; 00118 } 00119 00120 /* ========================================================== */ 00121 00122 void 00123 qof_sql_query_set_kvp (QofSqlQuery * q, KvpFrame * kvp) 00124 { 00125 if (!q) 00126 return; 00127 q->kvp_join = kvp; 00128 } 00129 00130 /* ========================================================== */ 00131 00132 static inline void 00133 get_table_and_param (char *str, char **tab, char **param) 00134 { 00135 char *end = strchr (str, '.'); 00136 if (!end) 00137 { 00138 *tab = 0; 00139 *param = str; 00140 return; 00141 } 00142 *end = 0; 00143 *tab = str; 00144 *param = end + 1; 00145 } 00146 00147 static inline char * 00148 dequote_string (char *str) 00149 { 00150 size_t len; 00151 /* strip out quotation marks ... */ 00152 if (('\'' == str[0]) || ('\"' == str[0])) 00153 { 00154 str++; 00155 len = strlen (str); 00156 str[len - 1] = 0; 00157 } 00158 return str; 00159 } 00160 00161 static QofQuery * 00162 handle_single_condition (QofSqlQuery * query, sql_condition * cond) 00163 { 00164 gchar tmpbuff[128]; 00165 GSList *param_list; 00166 GList *guid_list; 00167 QofQueryPredData *pred_data; 00168 sql_field_item *sparam, *svalue; 00169 gchar *qparam_name, *qvalue_name, *table_name, *param_name; 00170 gchar *sep, *path, *str, *p; 00171 QofQuery *qq; 00172 KvpValue *kv, *kval; 00173 KvpValueType kvt; 00174 QofQueryCompare qop; 00175 guint len; 00176 QofType param_type; 00177 QofGuidMatch gm; 00178 00179 pred_data = NULL; 00180 if (NULL == cond) 00181 { 00182 PWARN ("missing condition"); 00183 return NULL; 00184 } 00185 /* -------------------------------- */ 00186 /* field to match, assumed, for now to be on the left */ 00187 /* XXX fix this so it can be either left or right */ 00188 if (NULL == cond->d.pair.left) 00189 { 00190 PWARN ("missing left parameter"); 00191 return NULL; 00192 } 00193 sparam = cond->d.pair.left->item; 00194 if (SQL_name != sparam->type) 00195 { 00196 PWARN ("we support only parameter names at this time (parsed %d)", 00197 sparam->type); 00198 return NULL; 00199 } 00200 qparam_name = sparam->d.name->data; 00201 if (NULL == qparam_name) 00202 { 00203 PWARN ("missing parameter name"); 00204 return NULL; 00205 } 00206 00207 /* -------------------------------- */ 00208 /* value to match, assumed, for now, to be on the right. */ 00209 /* XXX fix this so it can be either left or right */ 00210 if (NULL == cond->d.pair.right) 00211 { 00212 PWARN ("missing right parameter"); 00213 return NULL; 00214 } 00215 svalue = cond->d.pair.right->item; 00216 if (SQL_name != svalue->type) 00217 { 00218 PWARN ("we support only simple values (parsed as %d)", 00219 svalue->type); 00220 return NULL; 00221 } 00222 qvalue_name = svalue->d.name->data; 00223 if (NULL == qvalue_name) 00224 { 00225 PWARN ("missing value"); 00226 return NULL; 00227 } 00228 qvalue_name = dequote_string (qvalue_name); 00229 qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name); 00230 00231 /* Look to see if its the special KVP value holder. 00232 * If it is, look up the value. */ 00233 if (0 == strncasecmp (qvalue_name, "kvp://", 6)) 00234 { 00235 if (NULL == query->kvp_join) 00236 { 00237 PWARN ("missing kvp frame"); 00238 return NULL; 00239 } 00240 kv = kvp_frame_get_value (query->kvp_join, qvalue_name + 5); 00241 /* If there's no value, its not an error; 00242 * we just don't do this predicate */ 00243 if (!kv) 00244 return NULL; 00245 kvt = kvp_value_get_type (kv); 00246 00247 tmpbuff[0] = 0x0; 00248 qvalue_name = tmpbuff; 00249 switch (kvt) 00250 { 00251 case KVP_TYPE_GINT64: 00252 { 00253 gint64 ival = kvp_value_get_gint64 (kv); 00254 sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival); 00255 break; 00256 } 00257 case KVP_TYPE_DOUBLE: 00258 { 00259 double ival = kvp_value_get_double (kv); 00260 sprintf (tmpbuff, "%26.18g\n", ival); 00261 break; 00262 } 00263 case KVP_TYPE_STRING: 00264 /* If there's no value, its not an error; 00265 * we just don't do this predicate */ 00266 qvalue_name = kvp_value_get_string (kv); 00267 if (!qvalue_name) 00268 return NULL; 00269 break; 00270 case KVP_TYPE_GUID: 00271 case KVP_TYPE_TIME : 00272 case KVP_TYPE_BOOLEAN : 00273 case KVP_TYPE_BINARY: 00274 case KVP_TYPE_GLIST: 00275 case KVP_TYPE_NUMERIC: 00276 case KVP_TYPE_FRAME: 00277 PWARN ("unhandled kvp type=%d", kvt); 00278 return NULL; 00279 } 00280 } 00281 00282 /* -------------------------------- */ 00283 /* Now start building the QOF parameter */ 00284 param_list = qof_query_build_param_list (qparam_name, NULL); 00285 00286 /* Get the where-term comparison operator */ 00287 switch (cond->op) 00288 { 00289 case SQL_eq: 00290 qop = QOF_COMPARE_EQUAL; 00291 break; 00292 case SQL_gt: 00293 qop = QOF_COMPARE_GT; 00294 break; 00295 case SQL_lt: 00296 qop = QOF_COMPARE_LT; 00297 break; 00298 case SQL_geq: 00299 qop = QOF_COMPARE_GTE; 00300 break; 00301 case SQL_leq: 00302 qop = QOF_COMPARE_LTE; 00303 break; 00304 case SQL_diff: 00305 qop = QOF_COMPARE_NEQ; 00306 break; 00307 default: 00308 /* XXX for string-type queries, we should be able to 00309 * support 'IN' for substring search. Also regex. */ 00310 PWARN ("Unsupported compare op (parsed as %u)", cond->op); 00311 return NULL; 00312 } 00313 00314 /* OK, need to know the type of the thing being matched 00315 * in order to build the correct predicate. Get the type 00316 * from the object parameters. */ 00317 get_table_and_param (qparam_name, &table_name, ¶m_name); 00318 if (NULL == table_name) 00319 { 00320 table_name = query->single_global_tablename; 00321 } 00322 if (NULL == table_name) 00323 { 00324 PWARN ("Need to specify an object class to query"); 00325 return NULL; 00326 } 00327 00328 if (FALSE == qof_class_is_registered (table_name)) 00329 { 00330 PWARN ("The query object \'%s\' is not known", table_name); 00331 return NULL; 00332 } 00333 00334 param_type = qof_class_get_parameter_type (table_name, param_name); 00335 if (!param_type) 00336 { 00337 PWARN ("The parameter \'%s\' on object \'%s\' is not known", 00338 param_name, table_name); 00339 return NULL; 00340 } 00341 00342 if (!strcmp (param_type, QOF_TYPE_STRING)) 00343 { 00344 pred_data = qof_query_string_predicate (qop, /* comparison to make */ 00345 qvalue_name, /* string to match */ 00346 QOF_STRING_MATCH_CASEINSENSITIVE, /* case matching */ 00347 FALSE); /* use_regexp */ 00348 } 00349 else if (!strcmp (param_type, QOF_TYPE_CHAR)) 00350 { 00351 QofCharMatch cm = QOF_CHAR_MATCH_ANY; 00352 if (QOF_COMPARE_NEQ == qop) 00353 cm = QOF_CHAR_MATCH_NONE; 00354 pred_data = qof_query_char_predicate (cm, qvalue_name); 00355 } 00356 else if (!strcmp (param_type, QOF_TYPE_INT32)) 00357 { 00358 gint32 ival = atoi (qvalue_name); 00359 pred_data = qof_query_int32_predicate (qop, ival); 00360 } 00361 else if (!strcmp (param_type, QOF_TYPE_INT64)) 00362 { 00363 gint64 ival = atoll (qvalue_name); 00364 pred_data = qof_query_int64_predicate (qop, ival); 00365 } 00366 else if (!strcmp (param_type, QOF_TYPE_DOUBLE)) 00367 { 00368 double ival = atof (qvalue_name); 00369 pred_data = qof_query_double_predicate (qop, ival); 00370 } 00371 else if (!strcmp (param_type, QOF_TYPE_BOOLEAN)) 00372 { 00373 gboolean ival = qof_util_bool_to_int (qvalue_name); 00374 pred_data = qof_query_boolean_predicate (qop, ival); 00375 } 00376 else if (!safe_strcmp (param_type, QOF_TYPE_TIME)) 00377 { 00378 QofDate *qd; 00379 QofTime *qt; 00380 00381 qd = qof_date_parse (qvalue_name, QOF_DATE_FORMAT_UTC); 00382 qt = qof_date_to_qtime (qd); 00383 qof_date_free (qd); 00384 pred_data = 00385 qof_query_time_predicate (qop, QOF_DATE_MATCH_NORMAL, 00386 qt); 00387 } 00388 else if (!strcmp (param_type, QOF_TYPE_NUMERIC)) 00389 { 00390 QofNumeric ival; 00391 qof_numeric_from_string (qvalue_name, &ival); 00392 pred_data = 00393 qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival); 00394 } 00395 else if (!strcmp (param_type, QOF_TYPE_DEBCRED)) 00396 { 00397 /* DEBCRED is likely to be deprecated before libqof2 */ 00398 QofNumeric ival; 00399 qof_numeric_from_string (qvalue_name, &ival); 00400 pred_data = 00401 qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival); 00402 } 00403 else if (!strcmp (param_type, QOF_TYPE_GUID)) 00404 { 00405 GUID guid; 00406 gboolean rc = string_to_guid (qvalue_name, &guid); 00407 if (0 == rc) 00408 { 00409 PWARN ("unable to parse guid: %s", qvalue_name); 00410 return NULL; 00411 } 00412 00413 // XXX less, than greater than don't make sense, 00414 // should check for those bad conditions 00415 00416 gm = QOF_GUID_MATCH_ANY; 00417 if (QOF_COMPARE_NEQ == qop) 00418 gm = QOF_GUID_MATCH_NONE; 00419 guid_list = g_list_append (NULL, &guid); 00420 pred_data = qof_query_guid_predicate (gm, guid_list); 00421 00422 g_list_free (guid_list); 00423 } 00424 else if (!strcmp (param_type, QOF_TYPE_KVP)) 00425 { 00426 /* We are expecting an encoded value that looks like 00427 * /some/path/string:value 00428 */ 00429 sep = strchr (qvalue_name, ':'); 00430 if (!sep) 00431 return NULL; 00432 *sep = 0; 00433 path = qvalue_name; 00434 str = sep + 1; 00435 /* If str has only digits, we know its a plain number. 00436 * If its numbers and a decimal point, assume a float 00437 * If its numbers and a slash, assume numeric 00438 * If its 32 bytes of hex, assume GUID 00439 * If it looks like an iso date ... 00440 * else assume its a string. 00441 */ 00442 kval = NULL; 00443 len = strlen (str); 00444 if ((32 == len) && (32 == strspn (str, "0123456789abcdef"))) 00445 { 00446 GUID guid; 00447 string_to_guid (str, &guid); 00448 kval = kvp_value_new_guid (&guid); 00449 } 00450 else if (len == strspn (str, "0123456789")) 00451 { 00452 kval = kvp_value_new_gint64 (atoll (str)); 00453 } 00454 else if ((p = strchr (str, '.')) && 00455 ((len - 1) == (strspn (str, "0123456789") + 00456 strspn (p + 1, "0123456789")))) 00457 { 00458 kval = kvp_value_new_double (atof (str)); 00459 } 00460 00461 else if ((p = strchr (str, '/')) && 00462 ((len - 1) == (strspn (str, "0123456789") + 00463 strspn (p + 1, "0123456789")))) 00464 { 00465 QofNumeric num; 00466 qof_numeric_from_string (str, &num); 00467 kval = kvp_value_new_numeric (num); 00468 } 00469 else if ((p = strchr (str, '-')) && 00470 (p = strchr (p + 1, '-')) && 00471 (p = strchr (p + 1, ' ')) && 00472 (p = strchr (p + 1, ':')) && (p = strchr (p + 1, ':'))) 00473 { 00474 QofDate *qd; 00475 QofTime *qt; 00476 00477 qd = qof_date_parse (str, QOF_DATE_FORMAT_UTC); 00478 qt = qof_date_to_qtime (qd); 00479 kval = 00480 kvp_value_new_time (qt); 00481 qof_date_free (qd); 00482 } 00483 00484 /* The default handler is a string */ 00485 if (NULL == kval) 00486 { 00487 kval = kvp_value_new_string (str); 00488 } 00489 pred_data = qof_query_kvp_predicate_path (qop, path, kval); 00490 } 00491 else 00492 { 00493 PWARN ("The predicate type \"%s\" is unsupported for now", 00494 param_type); 00495 return NULL; 00496 } 00497 00498 qq = qof_query_create (); 00499 qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM); 00500 return qq; 00501 } 00502 00503 /* ========================================================== */ 00504 00505 static QofQuery * 00506 handle_where (QofSqlQuery * query, sql_where * swear) 00507 { 00508 QofQueryOp qop; 00509 QofQuery *qq; 00510 00511 switch (swear->type) 00512 { 00513 case SQL_pair: 00514 { 00515 QofQuery *qleft = handle_where (query, swear->d.pair.left); 00516 QofQuery *qright = handle_where (query, swear->d.pair.right); 00517 if (NULL == qleft) 00518 return qright; 00519 if (NULL == qright) 00520 return qleft; 00521 switch (swear->d.pair.op) 00522 { 00523 case SQL_and: 00524 qop = QOF_QUERY_AND; 00525 break; 00526 case SQL_or: 00527 qop = QOF_QUERY_OR; 00528 break; 00529 /* XXX should add support for nand, nor, xor */ 00530 default: 00531 qof_query_destroy (qleft); 00532 qof_query_destroy (qright); 00533 return NULL; 00534 } 00535 qq = qof_query_merge (qleft, qright, qop); 00536 qof_query_destroy (qleft); 00537 qof_query_destroy (qright); 00538 return qq; 00539 } 00540 case SQL_negated: 00541 { 00542 QofQuery *qq = handle_where (query, swear->d.negated); 00543 QofQuery *qneg = qof_query_invert (qq); 00544 qof_query_destroy (qq); 00545 return qneg; 00546 } 00547 00548 case SQL_single: 00549 { 00550 sql_condition *cond = swear->d.single; 00551 return handle_single_condition (query, cond); 00552 } 00553 } 00554 return NULL; 00555 } 00556 00557 /* ========================================================== */ 00558 00559 static void 00560 handle_sort_order (QofSqlQuery * query, GList * sorder_list) 00561 { 00562 GSList *qsp[3]; 00563 GList *n; 00564 gboolean direction[3]; 00565 int i; 00566 sql_order_field *sorder; 00567 char *qparam_name; 00568 00569 if (!sorder_list) 00570 return; 00571 00572 for (i = 0; i < 3; i++) 00573 { 00574 qsp[i] = NULL; 00575 direction[i] = 0; 00576 00577 if (sorder_list) 00578 { 00579 sorder = sorder_list->data; 00580 00581 /* Set the sort direction */ 00582 if (SQL_asc == sorder->order_type) 00583 direction[i] = TRUE; 00584 00585 /* Find the parameter name */ 00586 qparam_name = NULL; 00587 n = sorder->name; 00588 if (n) 00589 { 00590 qparam_name = n->data; 00591 if (qparam_name) 00592 { 00593 qsp[i] = 00594 qof_query_build_param_list (qparam_name, NULL); 00595 } 00596 n = n->next; /* next parameter */ 00597 } 00598 else 00599 { 00600 /* if no next parameter, then next order-by */ 00601 sorder_list = sorder_list->next; 00602 } 00603 } 00604 } 00605 00606 qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]); 00607 qof_query_set_sort_increasing (query->qof_query, direction[0], 00608 direction[1], direction[2]); 00609 } 00610 00611 /* INSERT INTO handlers =================================================== */ 00612 00613 static void 00614 qof_sql_insertCB (const QofParam * param, const gchar * insert_string, 00615 QofSqlQuery * query) 00616 { 00617 QofIdTypeConst type; 00618 sql_insert_statement *sis; 00619 gboolean G_GNUC_UNUSED registered_type; 00620 QofEntity *ent; 00621 /* cm_ prefix used for variables that hold the data to commit */ 00622 QofNumeric cm_numeric; 00623 gdouble cm_double; 00624 gboolean cm_boolean; 00625 gint32 cm_i32; 00626 gint64 cm_i64; 00627 gchar cm_char, *tail; 00628 GUID *cm_guid; 00629 /* KvpFrame *cm_kvp; 00630 KvpValue *cm_value; 00631 KvpValueType cm_type;*/ 00632 void (*string_setter) (QofEntity *, const gchar *); 00633 void (*time_setter) (QofEntity *, QofTime *); 00634 void (*numeric_setter) (QofEntity *, QofNumeric); 00635 void (*double_setter) (QofEntity *, gdouble); 00636 void (*boolean_setter) (QofEntity *, gboolean); 00637 void (*i32_setter) (QofEntity *, gint32); 00638 void (*i64_setter) (QofEntity *, gint64); 00639 void (*char_setter) (QofEntity *, gchar); 00640 /* void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/ 00641 00642 g_return_if_fail (param || insert_string || query); 00643 ent = query->inserted_entity; 00644 sis = query->parse_result->statement; 00645 type = g_strdup_printf ("%s", sis->table->d.simple); 00646 00647 ENTER (" param=%s param_type=%s type=%s content=%s", 00648 param->param_name, param->param_type, type, insert_string); 00649 if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0) 00650 { 00651 string_setter = 00652 (void (*)(QofEntity *, const char *)) param->param_setfcn; 00653 if (string_setter != NULL) 00654 { 00655 string_setter (ent, insert_string); 00656 } 00657 registered_type = TRUE; 00658 } 00659 if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0) 00660 { 00661 QofDate *qd; 00662 QofTime *qt; 00663 time_setter = 00664 (void (*)(QofEntity *, QofTime *)) param->param_setfcn; 00665 qd = qof_date_parse (insert_string, QOF_DATE_FORMAT_UTC); 00666 qt = qof_date_to_qtime (qd); 00667 if((time_setter != NULL) && (qof_time_is_valid(qt))) 00668 { 00669 time_setter (ent, qt); 00670 } 00671 } 00672 if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) || 00673 (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0)) 00674 { 00675 numeric_setter = 00676 (void (*)(QofEntity *, QofNumeric)) param->param_setfcn; 00677 qof_numeric_from_string (insert_string, &cm_numeric); 00678 if (numeric_setter != NULL) 00679 { 00680 numeric_setter (ent, cm_numeric); 00681 } 00682 } 00683 if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0) 00684 { 00685 cm_guid = g_new (GUID, 1); 00686 if (TRUE != string_to_guid (insert_string, cm_guid)) 00687 { 00688 LEAVE (" string to guid failed for %s", insert_string); 00689 return; 00690 } 00691 /* reference_type = xmlGetProp(node, QSF_OBJECT_TYPE); 00692 if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type)) 00693 { 00694 qof_entity_set_guid(qsf_ent, cm_guid); 00695 } 00696 else { 00697 reference = qof_entity_get_reference_from(qsf_ent, cm_param); 00698 if(reference) { 00699 params->referenceList = g_list_append(params->referenceList, reference); 00700 } 00701 }*/ 00702 } 00703 if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0) 00704 { 00705 errno = 0; 00706 cm_i32 = (gint32) strtol (insert_string, &tail, 0); 00707 if (errno == 0) 00708 { 00709 i32_setter = 00710 (void (*)(QofEntity *, gint32)) param->param_setfcn; 00711 if (i32_setter != NULL) 00712 { 00713 i32_setter (ent, cm_i32); 00714 } 00715 } 00716 else 00717 { 00718 QofBackend *backend; 00719 QofBook *book; 00720 00721 book = qof_instance_get_book ((QofInstance *) ent); 00722 backend = qof_book_get_backend (book); 00723 qof_error_set_be (backend, qof_error_register 00724 (_("When converting SQLite strings into numbers, an " 00725 "overflow has been detected. The SQLite database " 00726 "'%s' contains invalid data in a field that is meant " 00727 "to hold a number."), TRUE)); 00728 } 00729 } 00730 if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0) 00731 { 00732 errno = 0; 00733 cm_i64 = strtoll (insert_string, &tail, 0); 00734 if (errno == 0) 00735 { 00736 i64_setter = 00737 (void (*)(QofEntity *, gint64)) param->param_setfcn; 00738 if (i64_setter != NULL) 00739 { 00740 i64_setter (ent, cm_i64); 00741 } 00742 } 00743 else 00744 { 00745 QofBackend *backend; 00746 QofBook *book; 00747 00748 book = qof_instance_get_book ((QofInstance *) ent); 00749 backend = qof_book_get_backend (book); 00750 qof_error_set_be (backend, qof_error_register 00751 (_("When converting SQLite strings into numbers, an " 00752 "overflow has been detected. The SQLite database " 00753 "'%s' contains invalid data in a field that is meant " 00754 "to hold a number."), TRUE)); 00755 } 00756 } 00757 if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0) 00758 { 00759 errno = 0; 00760 cm_double = strtod (insert_string, &tail); 00761 if (errno == 0) 00762 { 00763 double_setter = 00764 (void (*)(QofEntity *, double)) param->param_setfcn; 00765 if (double_setter != NULL) 00766 { 00767 double_setter (ent, cm_double); 00768 } 00769 } 00770 } 00771 if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0) 00772 { 00773 gint b; 00774 b = qof_util_bool_to_int (insert_string); 00775 if (b == 1) 00776 { 00777 cm_boolean = TRUE; 00778 } 00779 else 00780 { 00781 cm_boolean = FALSE; 00782 } 00783 boolean_setter = 00784 (void (*)(QofEntity *, gboolean)) param->param_setfcn; 00785 if (boolean_setter != NULL) 00786 { 00787 boolean_setter (ent, cm_boolean); 00788 } 00789 } 00790 if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0) 00791 { 00792 00793 } 00794 if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0) 00795 { 00796 cm_char = *insert_string; 00797 char_setter = (void (*)(QofEntity *, char)) param->param_setfcn; 00798 if (char_setter != NULL) 00799 { 00800 char_setter (ent, cm_char); 00801 } 00802 } 00803 LEAVE (" "); 00804 } 00805 00806 static void 00807 qof_query_set_insert_table (QofSqlQuery * query) 00808 { 00809 sql_insert_statement *sis; 00810 sql_table *sis_t; 00811 sis = query->parse_result->statement; 00812 switch (sis->table->type) 00813 { 00814 case SQL_simple: 00815 { 00816 sis_t = sis->table; 00817 query->single_global_tablename = 00818 g_strdup_printf ("%s", sis_t->d.simple); 00819 qof_query_search_for (query->qof_query, 00820 query->single_global_tablename); 00821 PINFO (" insert set to table: %s", sis_t->d.simple); 00822 break; 00823 } 00824 default: 00825 { 00826 PWARN ("SQL insert only handles simple statements"); 00827 } 00828 } 00829 } 00830 00831 static QofEntity * 00832 qof_query_insert (QofSqlQuery * query) 00833 { 00834 GList *field_list, *value_list, *cur; 00835 const gchar *param_name; 00836 gchar *value; 00837 QofIdType type; 00838 const QofParam *param; 00839 QofInstance *inst; 00840 sql_insert_statement *sis; 00841 sql_field *field; 00842 sql_field_item *item; 00843 00844 ENTER (" "); 00845 query->param_list = NULL; 00846 type = NULL; 00847 param = NULL; 00848 value = NULL; 00849 field_list = NULL; 00850 value_list = NULL; 00851 param_name = NULL; 00852 sis = query->parse_result->statement; 00853 if (!sis->fields || !sis->values) 00854 { 00855 LEAVE (" NULL insert statement"); 00856 return NULL; 00857 } 00858 type = g_strdup (query->single_global_tablename); 00859 inst = (QofInstance *) qof_object_new_instance (type, query->book); 00860 if (inst == NULL) 00861 { 00862 LEAVE (" unable to create instance of type %s", type); 00863 return NULL; 00864 } 00865 query->inserted_entity = &inst->entity; 00866 value_list = sis->values; 00867 for (field_list = sis->fields; field_list != NULL; 00868 field_list = field_list->next) 00869 { 00870 field = value_list->data; 00871 item = field->item; 00872 for (cur = item->d.name; cur != NULL; cur = cur->next) 00873 { 00874 value = 00875 g_strdup_printf ("%s", 00876 dequote_string ((char *) cur->data)); 00877 } 00878 field = field_list->data; 00879 item = field->item; 00880 for (cur = item->d.name; cur != NULL; cur = cur->next) 00881 { 00882 param_name = g_strdup_printf ("%s", (char *) cur->data); 00883 param = qof_class_get_parameter (type, param_name); 00884 } 00885 if (param && value) 00886 { 00887 qof_sql_insertCB (param, value, query); 00888 } 00889 value_list = g_list_next (value_list); 00890 } 00891 LEAVE (" "); 00892 return query->inserted_entity; 00893 } 00894 00895 static const char * 00896 sql_type_as_string (sql_statement_type type) 00897 { 00898 switch (type) 00899 { 00900 case SQL_select: 00901 { 00902 return "SELECT"; 00903 } 00904 case SQL_insert: 00905 { 00906 return "INSERT"; 00907 } 00908 case SQL_delete: 00909 { 00910 return "DELETE"; 00911 } 00912 case SQL_update: 00913 { 00914 return "UPDATE"; 00915 } 00916 default: 00917 { 00918 return "unknown"; 00919 } 00920 } 00921 } 00922 00923 void 00924 qof_sql_query_parse (QofSqlQuery * query, const char *str) 00925 { 00926 GList *tables; 00927 char *buf; 00928 sql_select_statement *sss; 00929 sql_where *swear; 00930 00931 if (!query) 00932 return; 00933 ENTER (" "); 00934 /* Delete old query, if any */ 00935 if (query->qof_query) 00936 { 00937 qof_query_destroy (query->qof_query); 00938 sql_destroy (query->parse_result); 00939 query->qof_query = NULL; 00940 } 00941 00942 /* Parse the SQL string */ 00943 buf = g_strdup (str); 00944 query->parse_result = sql_parse (buf); 00945 g_free (buf); 00946 00947 if (!query->parse_result) 00948 { 00949 LEAVE ("parse error"); 00950 return; 00951 } 00952 00953 if ((SQL_select != query->parse_result->type) 00954 && (SQL_insert != query->parse_result->type)) 00955 { 00956 LEAVE 00957 ("currently, only SELECT or INSERT statements are supported, " 00958 "got type=%s", sql_type_as_string (query->parse_result->type)); 00959 return; 00960 } 00961 00962 /* If the user wrote "SELECT * FROM tablename WHERE ..." 00963 * then we have a single global tablename. But if the 00964 * user wrote "SELECT * FROM tableA, tableB WHERE ..." 00965 * then we don't have a single unique table-name. 00966 */ 00967 tables = sql_statement_get_tables (query->parse_result); 00968 if (1 == g_list_length (tables)) 00969 { 00970 query->single_global_tablename = tables->data; 00971 } 00972 /* if this is an insert, we're done with the parse. */ 00973 if (SQL_insert == query->parse_result->type) 00974 { 00975 query->qof_query = qof_query_create (); 00976 qof_query_set_insert_table (query); 00977 LEAVE (" insert statement parsed OK"); 00978 return; 00979 } 00980 sss = query->parse_result->statement; 00981 swear = sss->where; 00982 if (swear) 00983 { 00984 /* Walk over the where terms, turn them into QOF predicates */ 00985 query->qof_query = handle_where (query, swear); 00986 if (NULL == query->qof_query) 00987 { 00988 LEAVE (" no query found"); 00989 return; 00990 } 00991 } 00992 else 00993 { 00994 query->qof_query = qof_query_create (); 00995 } 00996 /* Provide support for different sort orders */ 00997 handle_sort_order (query, sss->order); 00998 00999 /* We also want to set the type of thing to search for. 01000 * SELECT * FROM table1, table2, ... is not supported. 01001 * Use sequential queries and build a partial book. 01002 */ 01003 qof_query_search_for (query->qof_query, 01004 query->single_global_tablename); 01005 LEAVE (" success"); 01006 } 01007 01008 /* ========================================================== */ 01009 01010 GList * 01011 qof_sql_query_run (QofSqlQuery * query, const char *str) 01012 { 01013 GList *results; 01014 01015 if (!query) 01016 return NULL; 01017 01018 qof_sql_query_parse (query, str); 01019 if (NULL == query->qof_query) 01020 { 01021 PINFO (" Null query"); 01022 return NULL; 01023 } 01024 01025 qof_query_set_book (query->qof_query, query->book); 01026 /* Maybe log this sucker */ 01027 if (qof_log_check (log_module, QOF_LOG_DETAIL)) 01028 { 01029 qof_query_print (query->qof_query); 01030 } 01031 if (SQL_insert == query->parse_result->type) 01032 { 01033 results = NULL; 01034 results = g_list_append (results, qof_query_insert (query)); 01035 return results; 01036 } 01037 01038 results = qof_query_run (query->qof_query); 01039 01040 return results; 01041 } 01042 01043 GList * 01044 qof_sql_query_rerun (QofSqlQuery * query) 01045 { 01046 GList *results; 01047 01048 if (!query) 01049 return NULL; 01050 01051 if (NULL == query->qof_query) 01052 return NULL; 01053 01054 qof_query_set_book (query->qof_query, query->book); 01055 01056 /* Maybe log this sucker */ 01057 if (qof_log_check (log_module, QOF_LOG_DETAIL)) 01058 { 01059 qof_query_print (query->qof_query); 01060 } 01061 01062 results = qof_query_run (query->qof_query); 01063 01064 return results; 01065 } 01066 01068 typedef struct ent_and_string 01069 { 01070 QofEntity * ent; 01071 gchar * str; 01072 gchar * kvp_str; 01073 gchar * full_kvp_path; 01074 }eas; 01075 01076 static gulong kvp_id = 0; 01077 static gboolean kvp_table_exists = FALSE; 01078 01079 static void 01080 create_sql_from_param_cb (QofParam * param, gpointer user_data) 01081 { 01082 eas * data; 01083 gchar * value; 01084 GList * references; 01085 01086 g_return_if_fail (param); 01087 data = (eas*) user_data; 01088 ENTER ("%s %s", data->ent->e_type, param->param_name); 01089 g_return_if_fail (data->ent); 01090 if (!data->str) 01091 data->str = g_strdup (""); 01092 /* avoid creating database fields for calculated values */ 01093 if (!param->param_setfcn) 01094 return; 01095 /* avoid setting KVP even if a param_setfcn has been set 01096 because a QofSetterFunc for KVP is quite pointless. */ 01097 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP)) 01098 return; 01099 references = qof_class_get_referenceList (data->ent->e_type); 01100 if (g_list_find (references, param)) 01101 { 01102 /* \bug will need to use QofEntityReference here 01103 if partial books are actually to be supported. */ 01104 QofEntity *e; 01105 e = param->param_getfcn (data->ent, param); 01106 value = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01107 guid_to_string_buff (qof_entity_get_guid (e), value); 01108 PINFO (" ref=%p GUID=%s", e, value); 01109 } 01110 else 01111 value = qof_util_param_to_string (data->ent, param); 01112 if (value) 01113 g_strescape (value, NULL); 01114 if (!value) 01115 value = g_strdup (""); 01116 if (!g_str_has_suffix (data->str, "(")) 01117 { 01118 gchar *tmp; 01119 tmp = g_strjoin ("", data->str, ", '", value, "'", NULL); 01120 g_free (data->str); 01121 data->str = tmp; 01122 } 01123 else 01124 { 01125 gchar * tmp; 01126 tmp = g_strjoin ("", data->str, "'", value, "'", NULL); 01127 g_free (data->str); 01128 data->str = tmp; 01129 } 01130 LEAVE ("%s", data->str); 01131 } 01132 01133 static gchar * 01134 string_param_to_sql (QofParam * param) 01135 { 01142 /* Handle the entity GUID. Ensure that reference GUIDs 01143 must not also try to be primary keys and can be NULL. */ 01144 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_GUID)) && 01145 (0 == safe_strcmp (param->param_name, QOF_PARAM_GUID))) 01146 return g_strdup_printf (" %s char(32) primary key not null", 01147 param->param_name); 01148 if (0 == safe_strcmp (param->param_type, QOF_TYPE_GUID)) 01149 return g_strdup_printf (" %s char(32)", param->param_name); 01150 /* avoid creating database fields for calculated values */ 01151 if (!param->param_setfcn) 01152 return NULL; 01153 if (0 == safe_strcmp (param->param_type, QOF_TYPE_STRING)) 01154 return g_strdup_printf (" %s mediumtext", param->param_name); 01155 if (0 == safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN)) 01156 return g_strdup_printf (" %s int", param->param_name); 01157 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_NUMERIC)) 01158 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DOUBLE)) 01159 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DEBCRED))) 01160 { 01161 return g_strdup_printf (" %s text", param->param_name); 01162 } 01163 if (0 == safe_strcmp (param->param_type, QOF_TYPE_INT32)) 01164 return g_strdup_printf (" %s int", param->param_name); 01165 if (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME)) 01166 return g_strdup_printf (" %s datetime", param->param_name); 01167 if (0 == safe_strcmp (param->param_type, QOF_TYPE_CHAR)) 01168 return g_strdup_printf (" %s char(1)", param->param_name); 01169 /* kvp data is stored separately - actually this is really 01170 a no-op because entities do not need a param_setfcn for kvp data. */ 01171 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP)) 01172 return g_strdup (""); 01175 if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT)) 01176 return g_strdup (""); 01177 // return g_strdup_printf (" %s char(32)", param->param_name); 01178 /* catch references */ 01179 return g_strdup_printf (" %s char(32)", param->param_name); 01180 } 01181 01182 /* used by create/insert */ 01183 static void 01184 string_param_foreach (QofParam * param, gpointer user_data) 01185 { 01186 gchar *p_str, * tmp; 01187 eas * data; 01188 01189 PINFO ("string_param_foreach:%s", param->param_name); 01190 data = (eas *)user_data; 01191 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_KVP)) && 01192 (kvp_table_exists == FALSE)) 01193 { 01194 g_free (data->kvp_str); 01195 data->kvp_str = 01196 g_strdup_printf (" CREATE TABLE %s (%s, %s, %s, %s, %s, %s", 01197 kvp_table_name, "kvp_id int primary key not null", 01198 "guid char(32)", "path mediumtext", "type mediumtext", 01199 "value text", END_DB_VERSION); 01200 return; 01201 } 01202 p_str = string_param_to_sql (param); 01203 /* skip empty values (no param_setfcn) */ 01204 if (!p_str) 01205 return; 01206 if (!data->str) 01207 data->str = g_strdup(""); 01208 tmp = g_strjoin ("", data->str, p_str, ",", NULL); 01209 g_free (data->str); 01210 data->str = tmp; 01211 g_free (p_str); 01212 } 01213 01219 static void 01220 create_param_list (QofParam * param, gpointer user_data) 01221 { 01222 eas * data = (eas *)user_data; 01223 g_return_if_fail (data->str); 01224 /* avoid creating database fields for calculated values */ 01225 if (!param->param_setfcn) 01226 return; 01227 /* avoid setting KVP even if a param_setfcn has been set 01228 because a QofSetterFunc for KVP is quite pointless. */ 01229 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP)) 01230 { 01231 PINFO (" kvp support tag"); 01232 return; 01233 } 01234 if (!g_str_has_suffix (data->str, "(")) 01235 { 01236 gchar *add; 01237 add = g_strconcat (data->str, ", ", param->param_name, NULL); 01238 g_free (data->str); 01239 data->str = add; 01240 } 01241 else 01242 { 01243 gchar * add; 01244 add = g_strjoin ("", data->str, param->param_name, NULL); 01245 g_free (data->str); 01246 data->str = add; 01247 } 01248 } 01249 01251 static void 01252 kvpvalue_to_sql_insert (const gchar * key, KvpValue * val, gpointer user_data) 01253 { 01254 eas * data; 01255 KvpValueType n; 01256 gchar * path; 01257 01258 path = g_strdup(""); 01259 ENTER (" "); 01260 data = (eas*)user_data; 01261 g_return_if_fail (key && val && data); 01262 n = kvp_value_get_type (val); 01263 switch (n) 01264 { 01265 case KVP_TYPE_GINT64: 01266 case KVP_TYPE_DOUBLE: 01267 case KVP_TYPE_NUMERIC: 01268 case KVP_TYPE_STRING: 01269 case KVP_TYPE_GUID: 01270 case KVP_TYPE_TIME: 01271 case KVP_TYPE_BOOLEAN: 01272 { 01273 path = g_strjoin ("/", data->full_kvp_path, key, NULL); 01274 data->str = 01275 g_strdup_printf ("'%s', '%s', '%s'", key, path, 01276 kvp_value_to_bare_string (val)); 01277 DEBUG (" %s", data->str); 01278 break; 01279 } 01280 case KVP_TYPE_FRAME: 01281 { 01282 path = g_strjoin ("/", data->full_kvp_path, key, NULL); 01283 g_free (data->full_kvp_path); 01284 data->full_kvp_path = path; 01285 kvp_frame_for_each_slot (kvp_value_get_frame (val), 01286 kvpvalue_to_sql_insert, data); 01287 break; 01288 } 01289 default: 01290 { 01291 PERR (" unsupported value = %d", kvp_value_get_type (val)); 01292 break; 01293 } 01294 } 01295 LEAVE (" %s", data->str); 01296 } 01297 01299 static void 01300 kvpvalue_to_sql_update (const gchar * key, KvpValue * val, gpointer user_data) 01301 { 01302 eas * data; 01303 KvpValueType n; 01304 gchar * path; 01305 01306 ENTER (" key=%s", key); 01307 data = (eas*)user_data; 01308 g_return_if_fail (key && val && data); 01309 n = kvp_value_get_type (val); 01310 switch (n) 01311 { 01312 case KVP_TYPE_GINT64: 01313 case KVP_TYPE_DOUBLE: 01314 case KVP_TYPE_NUMERIC: 01315 case KVP_TYPE_STRING: 01316 case KVP_TYPE_GUID: 01317 case KVP_TYPE_TIME: 01318 case KVP_TYPE_BOOLEAN: 01319 { 01320 path = g_strjoin ("/", data->full_kvp_path, key, NULL); 01321 data->str = 01322 g_strdup_printf ("type='%s', value='%s' WHERE path='%s' and ", 01323 key, kvp_value_to_bare_string (val), path); 01324 DEBUG (" %s", data->str); 01325 break; 01326 } 01327 case KVP_TYPE_FRAME: 01328 { 01329 path = g_strjoin ("/", data->full_kvp_path, key, NULL); 01330 g_free (data->full_kvp_path); 01331 data->full_kvp_path = path; 01332 kvp_frame_for_each_slot (kvp_value_get_frame (val), 01333 kvpvalue_to_sql_update, data); 01334 break; 01335 } 01336 default: 01337 { 01338 PERR (" unsupported value = %d", kvp_value_get_type (val)); 01339 break; 01340 } 01341 } 01342 LEAVE (" %s", data->str); 01343 } 01344 01345 gchar * 01346 qof_sql_object_create_table (QofObject * obj) 01347 { 01348 gchar * sql_str, * start; 01349 eas data; 01350 01351 if (!kvp_table_name) 01352 kvp_table_name = g_strdup(QSQL_KVP_TABLE); 01353 ENTER ("create table for %s", obj->e_type); 01354 start = g_strdup_printf ("CREATE TABLE %s (", obj->e_type); 01355 data.ent = NULL; 01356 data.str = g_strdup(""); 01357 data.kvp_str = g_strdup(""); 01358 qof_class_param_foreach (obj->e_type, string_param_foreach, &data); 01359 sql_str = g_strjoin ("", start, data.str, END_DB_VERSION, data.kvp_str, NULL); 01360 g_free (start); 01361 g_free (data.kvp_str); 01362 g_free (data.str); 01363 LEAVE ("sql_str=%s", sql_str); 01364 return sql_str; 01365 } 01366 01367 gchar * 01368 qof_sql_entity_create_table (QofEntity * ent) 01369 { 01370 gchar * sql_str, * start; 01371 eas data; 01372 01373 g_return_val_if_fail (ent, NULL); 01374 if (!kvp_table_name) 01375 kvp_table_name = g_strdup(QSQL_KVP_TABLE); 01376 ENTER ("create table for %s", ent->e_type); 01377 start = g_strdup_printf ("CREATE TABLE %s (", ent->e_type); 01378 data.ent = ent; 01379 data.str = g_strdup(""); 01380 data.kvp_str = g_strdup(""); 01381 qof_class_param_foreach (ent->e_type, string_param_foreach, &data); 01382 sql_str = g_strjoin ("", start, data.str, END_DB_VERSION, data.kvp_str, NULL); 01383 g_free (start); 01384 LEAVE ("sql_str=%s", sql_str); 01385 return sql_str; 01386 } 01387 01388 gchar * 01389 qof_sql_entity_insert (QofEntity * ent) 01390 { 01391 KvpFrame * slots; 01392 eas data; 01393 gchar * command, * fields, * values, *id, *gstr, *sql_str, *kvp; 01394 01395 data.ent = ent; 01396 data.str = g_strdup(""); 01397 if (!kvp_table_name) 01398 kvp_table_name = g_strdup(QSQL_KVP_TABLE); 01399 ENTER (" insert a single '%s'", ent->e_type); 01400 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01401 guid_to_string_buff (qof_instance_get_guid ((QofInstance *) ent), gstr); 01402 DEBUG (" guid=%s", gstr); 01403 command = g_strdup_printf ("INSERT into %s (guid ", ent->e_type); 01404 // store param list in fields 01405 qof_class_param_foreach (ent->e_type, create_param_list, &data); 01406 fields = g_strdup(data.str); 01407 // store param values in values 01408 g_free (data.str); 01409 data.str = g_strdup(""); 01410 data.full_kvp_path = g_strdup(""); 01411 qof_class_param_foreach (ent->e_type, create_sql_from_param_cb, &data); 01412 values = data.str; 01413 /* handle KVP */ 01414 kvp = g_strdup(""); 01415 slots = qof_instance_get_slots ((QofInstance *) ent); 01416 if (!kvp_frame_is_empty(slots)) 01417 { 01418 id = g_strdup_printf ("%lu", kvp_id); 01419 g_free (kvp); 01420 kvp_frame_for_each_slot (slots, kvpvalue_to_sql_insert, &data); 01421 kvp = g_strconcat (" INSERT into ", kvp_table_name, 01422 " (kvp_id, guid, type, path, value) VALUES ('", id, "', '", 01423 gstr, "', ", data.str, ");", NULL); 01424 /* increment the index value of the KVP table */ 01425 kvp_id++; 01426 g_free (data.str); 01427 } 01428 sql_str = g_strjoin ("", command, fields, ") VALUES ('", gstr, "' ", 01429 values, ");", kvp, NULL); 01430 g_free (command); 01431 g_free (fields); 01432 g_free (gstr); 01433 g_free (values); 01434 g_free (data.full_kvp_path); 01435 LEAVE ("sql_str=%s", sql_str); 01436 return sql_str; 01437 } 01438 01439 static void 01440 collect_kvp (QofEntity * ent, gpointer user_data) 01441 { 01442 KvpFrame * slots; 01443 KvpValue * collguid; 01444 gchar * gstr, * name, * key; 01445 const QofParam * G_GNUC_UNUSED param; 01446 01447 name = (gchar *) user_data; 01448 param = qof_class_get_parameter (ent->e_type, name); 01449 key = g_strconcat ("collection/", name, "/guid/", NULL); 01450 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01451 guid_to_string_buff (qof_instance_get_guid ((QofInstance*)ent), gstr); 01452 collguid = kvp_value_new_string(gstr); 01453 slots = qof_instance_get_slots((QofInstance*)ent); 01454 kvp_frame_set_value (slots, key, collguid); 01455 g_free (key); 01456 g_free (gstr); 01457 } 01458 01459 gchar * 01460 qof_sql_entity_update (QofEntity * ent) 01461 { 01462 gchar *gstr, * sql_str, * param_str; 01463 QofInstance * inst; 01464 const QofParam * param; 01465 inst = (QofInstance*)ent; 01466 01467 if (!inst->param) 01468 return NULL; 01469 ENTER (" modified %s param:%s", ent->e_type, inst->param->param_name); 01470 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01471 guid_to_string_buff (qof_instance_get_guid (inst), gstr); 01472 param = inst->param; 01473 if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT)) 01474 { 01475 gchar * name; 01476 QofCollection * coll; 01477 01478 coll = param->param_getfcn (ent, param); 01479 name = g_strdup (param->param_name); 01480 qof_collection_foreach (coll, collect_kvp, name); 01481 g_free (name); 01482 return NULL; 01483 } 01484 param_str = qof_util_param_to_string (ent, inst->param); 01485 if (param_str) 01486 g_strescape (param_str, NULL); 01487 sql_str = g_strconcat ("UPDATE ", ent->e_type, " SET ", 01488 inst->param->param_name, " = '", param_str, 01489 "' WHERE ", QOF_TYPE_GUID, "='", gstr, "';", NULL); 01490 LEAVE ("sql_str=%s", sql_str); 01491 return sql_str; 01492 } 01493 01494 gchar * 01495 qof_sql_entity_update_kvp (QofEntity * ent) 01496 { 01497 eas data; 01498 gchar *gstr, * sql_str; 01499 QofInstance * inst; 01500 gchar * start; 01501 KvpFrame * slots; 01502 inst = (QofInstance*)ent; 01503 01504 if (!inst->param) 01505 return NULL; 01506 sql_str = NULL; 01507 if (kvp_frame_is_empty (qof_instance_get_slots ((QofInstance*)ent))) 01508 return NULL; 01509 01510 ENTER (" modified %s param:%s", ent->e_type, inst->param->param_name); 01511 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01512 guid_to_string_buff (qof_instance_get_guid (inst), gstr); 01513 data.str = g_strdup(""); 01514 data.full_kvp_path = g_strdup(""); 01515 slots = qof_instance_get_slots ((QofInstance*)ent); 01516 start = g_strjoin ("", "UPDATE ", kvp_table_name, " SET ", NULL); 01519 kvp_frame_for_each_slot (slots, kvpvalue_to_sql_update, &data); 01520 sql_str = g_strjoin ("", start, data.str, " guid='", gstr, "';", NULL); 01521 g_free (start); 01522 g_free (data.full_kvp_path); 01523 g_free (data.str); 01524 LEAVE ("sql_str=%s", sql_str); 01525 return sql_str; 01526 } 01527 01528 gchar * 01529 qof_sql_entity_update_list (QofEntity * ent, GList **params) 01530 { 01531 return NULL; 01532 } 01533 01534 gchar * 01535 qof_sql_entity_delete (QofEntity * ent) 01536 { 01537 gchar * gstr, * sql_str; 01538 ENTER (" %s", ent->e_type); 01539 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 01540 guid_to_string_buff (qof_entity_get_guid (ent), gstr); 01541 sql_str = g_strconcat ("DELETE from ", ent->e_type, " WHERE ", 01542 QOF_TYPE_GUID, "='", gstr, "';", "DELETE from ", kvp_table_name, 01543 " WHERE kvp_id ", "='", gstr, "';", NULL); 01544 g_free (gstr); 01545 return sql_str; 01546 } 01547 01548 gchar * 01549 qof_sql_entity_drop_table (QofEntity * ent) 01550 { 01551 gchar * sql_str; 01552 ENTER (" drop table for '%s'", ent->e_type); 01553 sql_str = g_strdup_printf ("DROP TABLE %s;", ent->e_type); 01554 LEAVE ("sql_str=%s", sql_str); 01555 return sql_str; 01556 } 01557 01558 void qof_sql_entity_set_kvp_tablename (const gchar * name) 01559 { 01560 g_return_if_fail (name); 01561 kvp_table_name = g_strdup(name); 01562 } 01563 01564 void qof_sql_entity_set_kvp_id (gulong id) 01565 { 01566 kvp_id = id; 01567 } 01568 01569 gulong qof_sql_entity_get_kvp_id (void) 01570 { 01571 return kvp_id; 01572 } 01573 01574 void qof_sql_entity_set_kvp_exists (gboolean exist) 01575 { 01576 kvp_table_exists = exist; 01577 } 01578 01579 /* ========================== END OF FILE =================== */