00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00034 #include "config.h"
00035 #include <stdlib.h>
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
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
00187
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
00209
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
00232
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
00242
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
00265
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
00284 param_list = qof_query_build_param_list (qparam_name, NULL);
00285
00286
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
00309
00310 PWARN ("Unsupported compare op (parsed as %u)", cond->op);
00311 return NULL;
00312 }
00313
00314
00315
00316
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,
00345 qvalue_name,
00346 QOF_STRING_MATCH_CASEINSENSITIVE,
00347 FALSE);
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
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
00414
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
00427
00428
00429 sep = strchr (qvalue_name, ':');
00430 if (!sep)
00431 return NULL;
00432 *sep = 0;
00433 path = qvalue_name;
00434 str = sep + 1;
00435
00436
00437
00438
00439
00440
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
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
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
00582 if (SQL_asc == sorder->order_type)
00583 direction[i] = TRUE;
00584
00585
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;
00597 }
00598 else
00599 {
00600
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
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 registered_type;
00620 QofEntity *ent;
00621
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
00630
00631
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
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
00692
00693
00694
00695
00696
00697
00698
00699
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
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
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
00963
00964
00965
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
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
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
00997 handle_sort_order (query, sss->order);
00998
00999
01000
01001
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
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
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
01093 if (!param->param_setfcn)
01094 return;
01095
01096
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
01103
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
01143
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
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
01170
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
01178
01179 return g_strdup_printf (" %s char(32)", param->param_name);
01180 }
01181
01182
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
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
01225 if (!param->param_setfcn)
01226 return;
01227
01228
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
01405 qof_class_param_foreach (ent->e_type, create_param_list, &data);
01406 fields = g_strdup(data.str);
01407
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
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
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 * 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