QOF  0.8.7
qofsql.c
Go to the documentation of this file.
1 /********************************************************************\
2  * qofsql.c -- QOF client-side SQL parser *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20  * *
21 \********************************************************************/
22 
34 #include "config.h"
35 #include <stdlib.h> /* for working atoll */
36 #include <errno.h>
37 #include <glib.h>
38 #include <libintl.h>
39 #ifdef HAVE_GDA
40 #include <libsql/sql_parser.h>
41 #else
42 #include "sql_parser.h"
43 #endif
44 #include <time.h>
45 #include "qof.h"
46 #include "qofsql-p.h"
47 #include "qofquery-p.h"
48 
49 #define _(String) dgettext (GETTEXT_PACKAGE, String)
50 
51 static gchar * kvp_table_name = NULL;
52 
53 #define QSQL_KVP_TABLE "sql_kvp"
54 
55 #define END_DB_VERSION " dbversion int );"
56 
57 static QofLogModule log_module = QOF_MOD_QUERY;
58 
59 /* =================================================================== */
60 
61 struct _QofSqlQuery
62 {
63  sql_statement *parse_result;
64  QofQuery *qof_query;
65  QofBook *book;
66  gchar *single_global_tablename;
67  KvpFrame *kvp_join;
68  GList *param_list;
69  QofEntity *inserted_entity;
70 };
71 
72 /* ========================================================== */
73 
74 QofSqlQuery *
76 {
77  QofSqlQuery *sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
78 
79  sqn->qof_query = NULL;
80  sqn->parse_result = NULL;
81  sqn->book = NULL;
82  sqn->single_global_tablename = NULL;
83  sqn->kvp_join = NULL;
84 
85  return sqn;
86 }
87 
88 /* ========================================================== */
89 
90 void
91 qof_sql_query_destroy (QofSqlQuery * q)
92 {
93  if (!q)
94  return;
95  qof_query_destroy (q->qof_query);
96  sql_destroy (q->parse_result);
97  g_free (q);
98 }
99 
100 /* ========================================================== */
101 
102 QofQuery *
103 qof_sql_query_get_query (QofSqlQuery * q)
104 {
105  if (!q)
106  return NULL;
107  return q->qof_query;
108 }
109 
110 /* ========================================================== */
111 
112 void
113 qof_sql_query_set_book (QofSqlQuery * q, QofBook * book)
114 {
115  if (!q)
116  return;
117  q->book = book;
118 }
119 
120 /* ========================================================== */
121 
122 void
123 qof_sql_query_set_kvp (QofSqlQuery * q, KvpFrame * kvp)
124 {
125  if (!q)
126  return;
127  q->kvp_join = kvp;
128 }
129 
130 /* ========================================================== */
131 
132 static inline void
133 get_table_and_param (char *str, char **tab, char **param)
134 {
135  char *end = strchr (str, '.');
136  if (!end)
137  {
138  *tab = 0;
139  *param = str;
140  return;
141  }
142  *end = 0;
143  *tab = str;
144  *param = end + 1;
145 }
146 
147 static inline char *
148 dequote_string (char *str)
149 {
150  size_t len;
151  /* strip out quotation marks ... */
152  if (('\'' == str[0]) || ('\"' == str[0]))
153  {
154  str++;
155  len = strlen (str);
156  str[len - 1] = 0;
157  }
158  return str;
159 }
160 
161 static QofQuery *
162 handle_single_condition (QofSqlQuery * query, sql_condition * cond)
163 {
164  gchar tmpbuff[128];
165  GSList *param_list;
166  GList *guid_list;
167  QofQueryPredData *pred_data;
168  sql_field_item *sparam, *svalue;
169  gchar *qparam_name, *qvalue_name, *table_name, *param_name;
170  gchar *sep, *path, *str, *p;
171  QofQuery *qq;
172  KvpValue *kv, *kval;
173  KvpValueType kvt;
174  QofQueryCompare qop;
175  guint len;
176  QofType param_type;
177  QofGuidMatch gm;
178 
179  pred_data = NULL;
180  if (NULL == cond)
181  {
182  PWARN ("missing condition");
183  return NULL;
184  }
185  /* -------------------------------- */
186  /* field to match, assumed, for now to be on the left */
187  /* XXX fix this so it can be either left or right */
188  if (NULL == cond->d.pair.left)
189  {
190  PWARN ("missing left parameter");
191  return NULL;
192  }
193  sparam = cond->d.pair.left->item;
194  if (SQL_name != sparam->type)
195  {
196  PWARN ("we support only parameter names at this time (parsed %d)",
197  sparam->type);
198  return NULL;
199  }
200  qparam_name = sparam->d.name->data;
201  if (NULL == qparam_name)
202  {
203  PWARN ("missing parameter name");
204  return NULL;
205  }
206 
207  /* -------------------------------- */
208  /* value to match, assumed, for now, to be on the right. */
209  /* XXX fix this so it can be either left or right */
210  if (NULL == cond->d.pair.right)
211  {
212  PWARN ("missing right parameter");
213  return NULL;
214  }
215  svalue = cond->d.pair.right->item;
216  if (SQL_name != svalue->type)
217  {
218  PWARN ("we support only simple values (parsed as %d)",
219  svalue->type);
220  return NULL;
221  }
222  qvalue_name = svalue->d.name->data;
223  if (NULL == qvalue_name)
224  {
225  PWARN ("missing value");
226  return NULL;
227  }
228  qvalue_name = dequote_string (qvalue_name);
229  qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
230 
231  /* Look to see if its the special KVP value holder.
232  * If it is, look up the value. */
233  if (0 == strncasecmp (qvalue_name, "kvp://", 6))
234  {
235  if (NULL == query->kvp_join)
236  {
237  PWARN ("missing kvp frame");
238  return NULL;
239  }
240  kv = kvp_frame_get_value (query->kvp_join, qvalue_name + 5);
241  /* If there's no value, its not an error;
242  * we just don't do this predicate */
243  if (!kv)
244  return NULL;
245  kvt = kvp_value_get_type (kv);
246 
247  tmpbuff[0] = 0x0;
248  qvalue_name = tmpbuff;
249  switch (kvt)
250  {
251  case KVP_TYPE_GINT64:
252  {
253  gint64 ival = kvp_value_get_gint64 (kv);
254  sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival);
255  break;
256  }
257  case KVP_TYPE_DOUBLE:
258  {
259  double ival = kvp_value_get_double (kv);
260  sprintf (tmpbuff, "%26.18g\n", ival);
261  break;
262  }
263  case KVP_TYPE_STRING:
264  /* If there's no value, its not an error;
265  * we just don't do this predicate */
266  qvalue_name = kvp_value_get_string (kv);
267  if (!qvalue_name)
268  return NULL;
269  break;
270  case KVP_TYPE_GUID:
271  case KVP_TYPE_TIME :
272  case KVP_TYPE_BOOLEAN :
273  case KVP_TYPE_BINARY:
274  case KVP_TYPE_GLIST:
275  case KVP_TYPE_NUMERIC:
276  case KVP_TYPE_FRAME:
277  PWARN ("unhandled kvp type=%d", kvt);
278  return NULL;
279  }
280  }
281 
282  /* -------------------------------- */
283  /* Now start building the QOF parameter */
284  param_list = qof_query_build_param_list (qparam_name, NULL);
285 
286  /* Get the where-term comparison operator */
287  switch (cond->op)
288  {
289  case SQL_eq:
290  qop = QOF_COMPARE_EQUAL;
291  break;
292  case SQL_gt:
293  qop = QOF_COMPARE_GT;
294  break;
295  case SQL_lt:
296  qop = QOF_COMPARE_LT;
297  break;
298  case SQL_geq:
299  qop = QOF_COMPARE_GTE;
300  break;
301  case SQL_leq:
302  qop = QOF_COMPARE_LTE;
303  break;
304  case SQL_diff:
305  qop = QOF_COMPARE_NEQ;
306  break;
307  default:
308  /* XXX for string-type queries, we should be able to
309  * support 'IN' for substring search. Also regex. */
310  PWARN ("Unsupported compare op (parsed as %u)", cond->op);
311  return NULL;
312  }
313 
314  /* OK, need to know the type of the thing being matched
315  * in order to build the correct predicate. Get the type
316  * from the object parameters. */
317  get_table_and_param (qparam_name, &table_name, &param_name);
318  if (NULL == table_name)
319  {
320  table_name = query->single_global_tablename;
321  }
322  if (NULL == table_name)
323  {
324  PWARN ("Need to specify an object class to query");
325  return NULL;
326  }
327 
328  if (FALSE == qof_class_is_registered (table_name))
329  {
330  PWARN ("The query object \'%s\' is not known", table_name);
331  return NULL;
332  }
333 
334  param_type = qof_class_get_parameter_type (table_name, param_name);
335  if (!param_type)
336  {
337  PWARN ("The parameter \'%s\' on object \'%s\' is not known",
338  param_name, table_name);
339  return NULL;
340  }
341 
342  if (!strcmp (param_type, QOF_TYPE_STRING))
343  {
344  pred_data = qof_query_string_predicate (qop, /* comparison to make */
345  qvalue_name, /* string to match */
346  QOF_STRING_MATCH_CASEINSENSITIVE, /* case matching */
347  FALSE); /* use_regexp */
348  }
349  else if (!strcmp (param_type, QOF_TYPE_CHAR))
350  {
351  QofCharMatch cm = QOF_CHAR_MATCH_ANY;
352  if (QOF_COMPARE_NEQ == qop)
353  cm = QOF_CHAR_MATCH_NONE;
354  pred_data = qof_query_char_predicate (cm, qvalue_name);
355  }
356  else if (!strcmp (param_type, QOF_TYPE_INT32))
357  {
358  gint32 ival = atoi (qvalue_name);
359  pred_data = qof_query_int32_predicate (qop, ival);
360  }
361  else if (!strcmp (param_type, QOF_TYPE_INT64))
362  {
363  gint64 ival = atoll (qvalue_name);
364  pred_data = qof_query_int64_predicate (qop, ival);
365  }
366  else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
367  {
368  double ival = atof (qvalue_name);
369  pred_data = qof_query_double_predicate (qop, ival);
370  }
371  else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
372  {
373  gboolean ival = qof_util_bool_to_int (qvalue_name);
374  pred_data = qof_query_boolean_predicate (qop, ival);
375  }
376  else if (!safe_strcmp (param_type, QOF_TYPE_TIME))
377  {
378  QofDate *qd;
379  QofTime *qt;
380 
381  qd = qof_date_parse (qvalue_name, QOF_DATE_FORMAT_UTC);
382  qt = qof_date_to_qtime (qd);
383  qof_date_free (qd);
384  pred_data =
385  qof_query_time_predicate (qop, QOF_DATE_MATCH_NORMAL,
386  qt);
387  }
388  else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
389  {
390  QofNumeric ival;
391  qof_numeric_from_string (qvalue_name, &ival);
392  pred_data =
393  qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
394  }
395  else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
396  {
397  /* DEBCRED is likely to be deprecated before libqof2 */
398  QofNumeric ival;
399  qof_numeric_from_string (qvalue_name, &ival);
400  pred_data =
401  qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
402  }
403  else if (!strcmp (param_type, QOF_TYPE_GUID))
404  {
405  GUID guid;
406  gboolean rc = string_to_guid (qvalue_name, &guid);
407  if (0 == rc)
408  {
409  PWARN ("unable to parse guid: %s", qvalue_name);
410  return NULL;
411  }
412 
413  // XXX less, than greater than don't make sense,
414  // should check for those bad conditions
415 
416  gm = QOF_GUID_MATCH_ANY;
417  if (QOF_COMPARE_NEQ == qop)
418  gm = QOF_GUID_MATCH_NONE;
419  guid_list = g_list_append (NULL, &guid);
420  pred_data = qof_query_guid_predicate (gm, guid_list);
421 
422  g_list_free (guid_list);
423  }
424  else if (!strcmp (param_type, QOF_TYPE_KVP))
425  {
426  /* We are expecting an encoded value that looks like
427  * /some/path/string:value
428  */
429  sep = strchr (qvalue_name, ':');
430  if (!sep)
431  return NULL;
432  *sep = 0;
433  path = qvalue_name;
434  str = sep + 1;
435  /* If str has only digits, we know its a plain number.
436  * If its numbers and a decimal point, assume a float
437  * If its numbers and a slash, assume numeric
438  * If its 32 bytes of hex, assume GUID
439  * If it looks like an iso date ...
440  * else assume its a string.
441  */
442  kval = NULL;
443  len = strlen (str);
444  if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
445  {
446  GUID guid;
447  string_to_guid (str, &guid);
448  kval = kvp_value_new_guid (&guid);
449  }
450  else if (len == strspn (str, "0123456789"))
451  {
452  kval = kvp_value_new_gint64 (atoll (str));
453  }
454  else if ((p = strchr (str, '.')) &&
455  ((len - 1) == (strspn (str, "0123456789") +
456  strspn (p + 1, "0123456789"))))
457  {
458  kval = kvp_value_new_double (atof (str));
459  }
460 
461  else if ((p = strchr (str, '/')) &&
462  ((len - 1) == (strspn (str, "0123456789") +
463  strspn (p + 1, "0123456789"))))
464  {
465  QofNumeric num;
466  qof_numeric_from_string (str, &num);
467  kval = kvp_value_new_numeric (num);
468  }
469  else if ((p = strchr (str, '-')) &&
470  (p = strchr (p + 1, '-')) &&
471  (p = strchr (p + 1, ' ')) &&
472  (p = strchr (p + 1, ':')) && (p = strchr (p + 1, ':')))
473  {
474  QofDate *qd;
475  QofTime *qt;
476 
478  qt = qof_date_to_qtime (qd);
479  kval =
480  kvp_value_new_time (qt);
481  qof_date_free (qd);
482  }
483 
484  /* The default handler is a string */
485  if (NULL == kval)
486  {
487  kval = kvp_value_new_string (str);
488  }
489  pred_data = qof_query_kvp_predicate_path (qop, path, kval);
490  }
491  else
492  {
493  PWARN ("The predicate type \"%s\" is unsupported for now",
494  param_type);
495  return NULL;
496  }
497 
498  qq = qof_query_create ();
499  qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
500  return qq;
501 }
502 
503 /* ========================================================== */
504 
505 static QofQuery *
506 handle_where (QofSqlQuery * query, sql_where * swear)
507 {
508  QofQueryOp qop;
509  QofQuery *qq;
510 
511  switch (swear->type)
512  {
513  case SQL_pair:
514  {
515  QofQuery *qleft = handle_where (query, swear->d.pair.left);
516  QofQuery *qright = handle_where (query, swear->d.pair.right);
517  if (NULL == qleft)
518  return qright;
519  if (NULL == qright)
520  return qleft;
521  switch (swear->d.pair.op)
522  {
523  case SQL_and:
524  qop = QOF_QUERY_AND;
525  break;
526  case SQL_or:
527  qop = QOF_QUERY_OR;
528  break;
529  /* XXX should add support for nand, nor, xor */
530  default:
531  qof_query_destroy (qleft);
532  qof_query_destroy (qright);
533  return NULL;
534  }
535  qq = qof_query_merge (qleft, qright, qop);
536  qof_query_destroy (qleft);
537  qof_query_destroy (qright);
538  return qq;
539  }
540  case SQL_negated:
541  {
542  QofQuery *qq = handle_where (query, swear->d.negated);
543  QofQuery *qneg = qof_query_invert (qq);
544  qof_query_destroy (qq);
545  return qneg;
546  }
547 
548  case SQL_single:
549  {
550  sql_condition *cond = swear->d.single;
551  return handle_single_condition (query, cond);
552  }
553  }
554  return NULL;
555 }
556 
557 /* ========================================================== */
558 
559 static void
560 handle_sort_order (QofSqlQuery * query, GList * sorder_list)
561 {
562  GSList *qsp[3];
563  GList *n;
564  gboolean direction[3];
565  int i;
566  sql_order_field *sorder;
567  char *qparam_name;
568 
569  if (!sorder_list)
570  return;
571 
572  for (i = 0; i < 3; i++)
573  {
574  qsp[i] = NULL;
575  direction[i] = 0;
576 
577  if (sorder_list)
578  {
579  sorder = sorder_list->data;
580 
581  /* Set the sort direction */
582  if (SQL_asc == sorder->order_type)
583  direction[i] = TRUE;
584 
585  /* Find the parameter name */
586  qparam_name = NULL;
587  n = sorder->name;
588  if (n)
589  {
590  qparam_name = n->data;
591  if (qparam_name)
592  {
593  qsp[i] =
594  qof_query_build_param_list (qparam_name, NULL);
595  }
596  n = n->next; /* next parameter */
597  }
598  else
599  {
600  /* if no next parameter, then next order-by */
601  sorder_list = sorder_list->next;
602  }
603  }
604  }
605 
606  qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
607  qof_query_set_sort_increasing (query->qof_query, direction[0],
608  direction[1], direction[2]);
609 }
610 
611 /* INSERT INTO handlers =================================================== */
612 
613 static void
614 qof_sql_insertCB (const QofParam * param, const gchar * insert_string,
615  QofSqlQuery * query)
616 {
617  QofIdTypeConst type;
618  sql_insert_statement *sis;
619  gboolean G_GNUC_UNUSED registered_type;
620  QofEntity *ent;
621  /* cm_ prefix used for variables that hold the data to commit */
622  QofNumeric cm_numeric;
623  gdouble cm_double;
624  gboolean cm_boolean;
625  gint32 cm_i32;
626  gint64 cm_i64;
627  gchar cm_char, *tail;
628  GUID *cm_guid;
629 /* KvpFrame *cm_kvp;
630  KvpValue *cm_value;
631  KvpValueType cm_type;*/
632  void (*string_setter) (QofEntity *, const gchar *);
633  void (*time_setter) (QofEntity *, QofTime *);
634  void (*numeric_setter) (QofEntity *, QofNumeric);
635  void (*double_setter) (QofEntity *, gdouble);
636  void (*boolean_setter) (QofEntity *, gboolean);
637  void (*i32_setter) (QofEntity *, gint32);
638  void (*i64_setter) (QofEntity *, gint64);
639  void (*char_setter) (QofEntity *, gchar);
640 /* void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/
641 
642  g_return_if_fail (param || insert_string || query);
643  ent = query->inserted_entity;
644  sis = query->parse_result->statement;
645  type = g_strdup_printf ("%s", sis->table->d.simple);
646 
647  ENTER (" param=%s param_type=%s type=%s content=%s",
648  param->param_name, param->param_type, type, insert_string);
649  if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0)
650  {
651  string_setter =
652  (void (*)(QofEntity *, const char *)) param->param_setfcn;
653  if (string_setter != NULL)
654  {
655  string_setter (ent, insert_string);
656  }
657  registered_type = TRUE;
658  }
659  if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0)
660  {
661  QofDate *qd;
662  QofTime *qt;
663  time_setter =
664  (void (*)(QofEntity *, QofTime *)) param->param_setfcn;
665  qd = qof_date_parse (insert_string, QOF_DATE_FORMAT_UTC);
666  qt = qof_date_to_qtime (qd);
667  if((time_setter != NULL) && (qof_time_is_valid(qt)))
668  {
669  time_setter (ent, qt);
670  }
671  }
672  if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) ||
673  (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0))
674  {
675  numeric_setter =
676  (void (*)(QofEntity *, QofNumeric)) param->param_setfcn;
677  qof_numeric_from_string (insert_string, &cm_numeric);
678  if (numeric_setter != NULL)
679  {
680  numeric_setter (ent, cm_numeric);
681  }
682  }
683  if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0)
684  {
685  cm_guid = g_new (GUID, 1);
686  if (TRUE != string_to_guid (insert_string, cm_guid))
687  {
688  LEAVE (" string to guid failed for %s", insert_string);
689  return;
690  }
691 /* reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
692  if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
693  {
694  qof_entity_set_guid(qsf_ent, cm_guid);
695  }
696  else {
697  reference = qof_entity_get_reference_from(qsf_ent, cm_param);
698  if(reference) {
699  params->referenceList = g_list_append(params->referenceList, reference);
700  }
701  }*/
702  }
703  if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0)
704  {
705  errno = 0;
706  cm_i32 = (gint32) strtol (insert_string, &tail, 0);
707  if (errno == 0)
708  {
709  i32_setter =
710  (void (*)(QofEntity *, gint32)) param->param_setfcn;
711  if (i32_setter != NULL)
712  {
713  i32_setter (ent, cm_i32);
714  }
715  }
716  else
717  {
718  QofBackend *backend;
719  QofBook *book;
720 
721  book = qof_instance_get_book ((QofInstance *) ent);
722  backend = qof_book_get_backend (book);
723  qof_error_set_be (backend, qof_error_register
724  (_("When converting SQLite strings into numbers, an "
725  "overflow has been detected. The SQLite database "
726  "'%s' contains invalid data in a field that is meant "
727  "to hold a number."), TRUE));
728  }
729  }
730  if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0)
731  {
732  errno = 0;
733  cm_i64 = strtoll (insert_string, &tail, 0);
734  if (errno == 0)
735  {
736  i64_setter =
737  (void (*)(QofEntity *, gint64)) param->param_setfcn;
738  if (i64_setter != NULL)
739  {
740  i64_setter (ent, cm_i64);
741  }
742  }
743  else
744  {
745  QofBackend *backend;
746  QofBook *book;
747 
748  book = qof_instance_get_book ((QofInstance *) ent);
749  backend = qof_book_get_backend (book);
750  qof_error_set_be (backend, qof_error_register
751  (_("When converting SQLite strings into numbers, an "
752  "overflow has been detected. The SQLite database "
753  "'%s' contains invalid data in a field that is meant "
754  "to hold a number."), TRUE));
755  }
756  }
757  if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0)
758  {
759  errno = 0;
760  cm_double = strtod (insert_string, &tail);
761  if (errno == 0)
762  {
763  double_setter =
764  (void (*)(QofEntity *, double)) param->param_setfcn;
765  if (double_setter != NULL)
766  {
767  double_setter (ent, cm_double);
768  }
769  }
770  }
771  if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0)
772  {
773  gint b;
774  b = qof_util_bool_to_int (insert_string);
775  if (b == 1)
776  {
777  cm_boolean = TRUE;
778  }
779  else
780  {
781  cm_boolean = FALSE;
782  }
783  boolean_setter =
784  (void (*)(QofEntity *, gboolean)) param->param_setfcn;
785  if (boolean_setter != NULL)
786  {
787  boolean_setter (ent, cm_boolean);
788  }
789  }
790  if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0)
791  {
792 
793  }
794  if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0)
795  {
796  cm_char = *insert_string;
797  char_setter = (void (*)(QofEntity *, char)) param->param_setfcn;
798  if (char_setter != NULL)
799  {
800  char_setter (ent, cm_char);
801  }
802  }
803  LEAVE (" ");
804 }
805 
806 static void
807 qof_query_set_insert_table (QofSqlQuery * query)
808 {
809  sql_insert_statement *sis;
810  sql_table *sis_t;
811  sis = query->parse_result->statement;
812  switch (sis->table->type)
813  {
814  case SQL_simple:
815  {
816  sis_t = sis->table;
817  query->single_global_tablename =
818  g_strdup_printf ("%s", sis_t->d.simple);
819  qof_query_search_for (query->qof_query,
820  query->single_global_tablename);
821  PINFO (" insert set to table: %s", sis_t->d.simple);
822  break;
823  }
824  default:
825  {
826  PWARN ("SQL insert only handles simple statements");
827  }
828  }
829 }
830 
831 static QofEntity *
832 qof_query_insert (QofSqlQuery * query)
833 {
834  GList *field_list, *value_list, *cur;
835  const gchar *param_name;
836  gchar *value;
837  QofIdType type;
838  const QofParam *param;
839  QofInstance *inst;
840  sql_insert_statement *sis;
841  sql_field *field;
842  sql_field_item *item;
843 
844  ENTER (" ");
845  query->param_list = NULL;
846  type = NULL;
847  param = NULL;
848  value = NULL;
849  field_list = NULL;
850  value_list = NULL;
851  param_name = NULL;
852  sis = query->parse_result->statement;
853  if (!sis->fields || !sis->values)
854  {
855  LEAVE (" NULL insert statement");
856  return NULL;
857  }
858  type = g_strdup (query->single_global_tablename);
859  inst = (QofInstance *) qof_object_new_instance (type, query->book);
860  if (inst == NULL)
861  {
862  LEAVE (" unable to create instance of type %s", type);
863  return NULL;
864  }
865  query->inserted_entity = &inst->entity;
866  value_list = sis->values;
867  for (field_list = sis->fields; field_list != NULL;
868  field_list = field_list->next)
869  {
870  field = value_list->data;
871  item = field->item;
872  for (cur = item->d.name; cur != NULL; cur = cur->next)
873  {
874  value =
875  g_strdup_printf ("%s",
876  dequote_string ((char *) cur->data));
877  }
878  field = field_list->data;
879  item = field->item;
880  for (cur = item->d.name; cur != NULL; cur = cur->next)
881  {
882  param_name = g_strdup_printf ("%s", (char *) cur->data);
883  param = qof_class_get_parameter (type, param_name);
884  }
885  if (param && value)
886  {
887  qof_sql_insertCB (param, value, query);
888  }
889  value_list = g_list_next (value_list);
890  }
891  LEAVE (" ");
892  return query->inserted_entity;
893 }
894 
895 static const char *
896 sql_type_as_string (sql_statement_type type)
897 {
898  switch (type)
899  {
900  case SQL_select:
901  {
902  return "SELECT";
903  }
904  case SQL_insert:
905  {
906  return "INSERT";
907  }
908  case SQL_delete:
909  {
910  return "DELETE";
911  }
912  case SQL_update:
913  {
914  return "UPDATE";
915  }
916  default:
917  {
918  return "unknown";
919  }
920  }
921 }
922 
923 void
924 qof_sql_query_parse (QofSqlQuery * query, const char *str)
925 {
926  GList *tables;
927  char *buf;
928  sql_select_statement *sss;
929  sql_where *swear;
930 
931  if (!query)
932  return;
933  ENTER (" ");
934  /* Delete old query, if any */
935  if (query->qof_query)
936  {
937  qof_query_destroy (query->qof_query);
938  sql_destroy (query->parse_result);
939  query->qof_query = NULL;
940  }
941 
942  /* Parse the SQL string */
943  buf = g_strdup (str);
944  query->parse_result = sql_parse (buf);
945  g_free (buf);
946 
947  if (!query->parse_result)
948  {
949  LEAVE ("parse error");
950  return;
951  }
952 
953  if ((SQL_select != query->parse_result->type)
954  && (SQL_insert != query->parse_result->type))
955  {
956  LEAVE
957  ("currently, only SELECT or INSERT statements are supported, "
958  "got type=%s", sql_type_as_string (query->parse_result->type));
959  return;
960  }
961 
962  /* If the user wrote "SELECT * FROM tablename WHERE ..."
963  * then we have a single global tablename. But if the
964  * user wrote "SELECT * FROM tableA, tableB WHERE ..."
965  * then we don't have a single unique table-name.
966  */
967  tables = sql_statement_get_tables (query->parse_result);
968  if (1 == g_list_length (tables))
969  {
970  query->single_global_tablename = tables->data;
971  }
972  /* if this is an insert, we're done with the parse. */
973  if (SQL_insert == query->parse_result->type)
974  {
975  query->qof_query = qof_query_create ();
976  qof_query_set_insert_table (query);
977  LEAVE (" insert statement parsed OK");
978  return;
979  }
980  sss = query->parse_result->statement;
981  swear = sss->where;
982  if (swear)
983  {
984  /* Walk over the where terms, turn them into QOF predicates */
985  query->qof_query = handle_where (query, swear);
986  if (NULL == query->qof_query)
987  {
988  LEAVE (" no query found");
989  return;
990  }
991  }
992  else
993  {
994  query->qof_query = qof_query_create ();
995  }
996  /* Provide support for different sort orders */
997  handle_sort_order (query, sss->order);
998 
999  /* We also want to set the type of thing to search for.
1000  * SELECT * FROM table1, table2, ... is not supported.
1001  * Use sequential queries and build a partial book.
1002  */
1003  qof_query_search_for (query->qof_query,
1004  query->single_global_tablename);
1005  LEAVE (" success");
1006 }
1007 
1008 /* ========================================================== */
1009 
1010 GList *
1011 qof_sql_query_run (QofSqlQuery * query, const char *str)
1012 {
1013  GList *results;
1014 
1015  if (!query)
1016  return NULL;
1017 
1018  qof_sql_query_parse (query, str);
1019  if (NULL == query->qof_query)
1020  {
1021  PINFO (" Null query");
1022  return NULL;
1023  }
1024 
1025  qof_query_set_book (query->qof_query, query->book);
1026  /* Maybe log this sucker */
1027  if (qof_log_check (log_module, QOF_LOG_DETAIL))
1028  {
1029  qof_query_print (query->qof_query);
1030  }
1031  if (SQL_insert == query->parse_result->type)
1032  {
1033  results = NULL;
1034  results = g_list_append (results, qof_query_insert (query));
1035  return results;
1036  }
1037 
1038  results = qof_query_run (query->qof_query);
1039 
1040  return results;
1041 }
1042 
1043 GList *
1044 qof_sql_query_rerun (QofSqlQuery * query)
1045 {
1046  GList *results;
1047 
1048  if (!query)
1049  return NULL;
1050 
1051  if (NULL == query->qof_query)
1052  return NULL;
1053 
1054  qof_query_set_book (query->qof_query, query->book);
1055 
1056  /* Maybe log this sucker */
1057  if (qof_log_check (log_module, QOF_LOG_DETAIL))
1058  {
1059  qof_query_print (query->qof_query);
1060  }
1061 
1062  results = qof_query_run (query->qof_query);
1063 
1064  return results;
1065 }
1066 
1068 typedef struct ent_and_string
1069 {
1070  QofEntity * ent;
1071  gchar * str;
1072  gchar * kvp_str;
1073  gchar * full_kvp_path;
1074 }eas;
1075 
1076 static gulong kvp_id = 0;
1077 static gboolean kvp_table_exists = FALSE;
1078 
1079 static void
1080 create_sql_from_param_cb (QofParam * param, gpointer user_data)
1081 {
1082  eas * data;
1083  gchar * value;
1084  GList * references;
1085 
1086  g_return_if_fail (param);
1087  data = (eas*) user_data;
1088  ENTER ("%s %s", data->ent->e_type, param->param_name);
1089  g_return_if_fail (data->ent);
1090  if (!data->str)
1091  data->str = g_strdup ("");
1092  /* avoid creating database fields for calculated values */
1093  if (!param->param_setfcn)
1094  return;
1095  /* avoid setting KVP even if a param_setfcn has been set
1096  because a QofSetterFunc for KVP is quite pointless. */
1097  if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
1098  return;
1099  references = qof_class_get_referenceList (data->ent->e_type);
1100  if (g_list_find (references, param))
1101  {
1102  /* \bug will need to use QofEntityReference here
1103  if partial books are actually to be supported. */
1104  QofEntity *e;
1105  e = param->param_getfcn (data->ent, param);
1106  value = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1108  PINFO (" ref=%p GUID=%s", e, value);
1109  }
1110  else
1111  value = qof_util_param_to_string (data->ent, param);
1112  if (value)
1113  g_strescape (value, NULL);
1114  if (!value)
1115  value = g_strdup ("");
1116  if (!g_str_has_suffix (data->str, "("))
1117  {
1118  gchar *tmp;
1119  tmp = g_strjoin ("", data->str, ", '", value, "'", NULL);
1120  g_free (data->str);
1121  data->str = tmp;
1122  }
1123  else
1124  {
1125  gchar * tmp;
1126  tmp = g_strjoin ("", data->str, "'", value, "'", NULL);
1127  g_free (data->str);
1128  data->str = tmp;
1129  }
1130  LEAVE ("%s", data->str);
1131 }
1132 
1133 static gchar *
1135 {
1142  /* Handle the entity GUID. Ensure that reference GUIDs
1143  must not also try to be primary keys and can be NULL. */
1144  if ((0 == safe_strcmp (param->param_type, QOF_TYPE_GUID)) &&
1145  (0 == safe_strcmp (param->param_name, QOF_PARAM_GUID)))
1146  return g_strdup_printf (" %s char(32) primary key not null",
1147  param->param_name);
1148  if (0 == safe_strcmp (param->param_type, QOF_TYPE_GUID))
1149  return g_strdup_printf (" %s char(32)", param->param_name);
1150  /* avoid creating database fields for calculated values */
1151  if (!param->param_setfcn)
1152  return NULL;
1153  if (0 == safe_strcmp (param->param_type, QOF_TYPE_STRING))
1154  return g_strdup_printf (" %s mediumtext", param->param_name);
1155  if (0 == safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN))
1156  return g_strdup_printf (" %s int", param->param_name);
1157  if ((0 == safe_strcmp (param->param_type, QOF_TYPE_NUMERIC))
1158  || (0 == safe_strcmp (param->param_type, QOF_TYPE_DOUBLE))
1159  || (0 == safe_strcmp (param->param_type, QOF_TYPE_DEBCRED)))
1160  {
1161  return g_strdup_printf (" %s text", param->param_name);
1162  }
1163  if (0 == safe_strcmp (param->param_type, QOF_TYPE_INT32))
1164  return g_strdup_printf (" %s int", param->param_name);
1165  if (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME))
1166  return g_strdup_printf (" %s datetime", param->param_name);
1167  if (0 == safe_strcmp (param->param_type, QOF_TYPE_CHAR))
1168  return g_strdup_printf (" %s char(1)", param->param_name);
1169  /* kvp data is stored separately - actually this is really
1170  a no-op because entities do not need a param_setfcn for kvp data. */
1171  if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
1172  return g_strdup ("");
1175  if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT))
1176  return g_strdup ("");
1177 // return g_strdup_printf (" %s char(32)", param->param_name);
1178  /* catch references */
1179  return g_strdup_printf (" %s char(32)", param->param_name);
1180 }
1181 
1182 /* used by create/insert */
1183 static void
1184 string_param_foreach (QofParam * param, gpointer user_data)
1185 {
1186  gchar *p_str, * tmp;
1187  eas * data;
1188 
1189  PINFO ("string_param_foreach:%s", param->param_name);
1190  data = (eas *)user_data;
1191  if ((0 == safe_strcmp (param->param_type, QOF_TYPE_KVP)) &&
1192  (kvp_table_exists == FALSE))
1193  {
1194  g_free (data->kvp_str);
1195  data->kvp_str =
1196  g_strdup_printf (" CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
1197  kvp_table_name, "kvp_id int primary key not null",
1198  "guid char(32)", "path mediumtext", "type mediumtext",
1199  "value text", END_DB_VERSION);
1200  return;
1201  }
1202  p_str = string_param_to_sql (param);
1203  /* skip empty values (no param_setfcn) */
1204  if (!p_str)
1205  return;
1206  if (!data->str)
1207  data->str = g_strdup("");
1208  tmp = g_strjoin ("", data->str, p_str, ",", NULL);
1209  g_free (data->str);
1210  data->str = tmp;
1211  g_free (p_str);
1212 }
1213 
1219 static void
1220 create_param_list (QofParam * param, gpointer user_data)
1221 {
1222  eas * data = (eas *)user_data;
1223  g_return_if_fail (data->str);
1224  /* avoid creating database fields for calculated values */
1225  if (!param->param_setfcn)
1226  return;
1227  /* avoid setting KVP even if a param_setfcn has been set
1228  because a QofSetterFunc for KVP is quite pointless. */
1229  if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
1230  {
1231  PINFO (" kvp support tag");
1232  return;
1233  }
1234  if (!g_str_has_suffix (data->str, "("))
1235  {
1236  gchar *add;
1237  add = g_strconcat (data->str, ", ", param->param_name, NULL);
1238  g_free (data->str);
1239  data->str = add;
1240  }
1241  else
1242  {
1243  gchar * add;
1244  add = g_strjoin ("", data->str, param->param_name, NULL);
1245  g_free (data->str);
1246  data->str = add;
1247  }
1248 }
1249 
1251 static void
1252 kvpvalue_to_sql_insert (const gchar * key, KvpValue * val, gpointer user_data)
1253 {
1254  eas * data;
1255  KvpValueType n;
1256  gchar * path;
1257 
1258  path = g_strdup("");
1259  ENTER (" ");
1260  data = (eas*)user_data;
1261  g_return_if_fail (key && val && data);
1262  n = kvp_value_get_type (val);
1263  switch (n)
1264  {
1265  case KVP_TYPE_GINT64:
1266  case KVP_TYPE_DOUBLE:
1267  case KVP_TYPE_NUMERIC:
1268  case KVP_TYPE_STRING:
1269  case KVP_TYPE_GUID:
1270  case KVP_TYPE_TIME:
1271  case KVP_TYPE_BOOLEAN:
1272  {
1273  path = g_strjoin ("/", data->full_kvp_path, key, NULL);
1274  data->str =
1275  g_strdup_printf ("'%s', '%s', '%s'", key, path,
1276  kvp_value_to_bare_string (val));
1277  DEBUG (" %s", data->str);
1278  break;
1279  }
1280  case KVP_TYPE_FRAME:
1281  {
1282  path = g_strjoin ("/", data->full_kvp_path, key, NULL);
1283  g_free (data->full_kvp_path);
1284  data->full_kvp_path = path;
1286  kvpvalue_to_sql_insert, data);
1287  break;
1288  }
1289  default:
1290  {
1291  PERR (" unsupported value = %d", kvp_value_get_type (val));
1292  break;
1293  }
1294  }
1295  LEAVE (" %s", data->str);
1296 }
1297 
1299 static void
1300 kvpvalue_to_sql_update (const gchar * key, KvpValue * val, gpointer user_data)
1301 {
1302  eas * data;
1303  KvpValueType n;
1304  gchar * path;
1305 
1306  ENTER (" key=%s", key);
1307  data = (eas*)user_data;
1308  g_return_if_fail (key && val && data);
1309  n = kvp_value_get_type (val);
1310  switch (n)
1311  {
1312  case KVP_TYPE_GINT64:
1313  case KVP_TYPE_DOUBLE:
1314  case KVP_TYPE_NUMERIC:
1315  case KVP_TYPE_STRING:
1316  case KVP_TYPE_GUID:
1317  case KVP_TYPE_TIME:
1318  case KVP_TYPE_BOOLEAN:
1319  {
1320  path = g_strjoin ("/", data->full_kvp_path, key, NULL);
1321  data->str =
1322  g_strdup_printf ("type='%s', value='%s' WHERE path='%s' and ",
1323  key, kvp_value_to_bare_string (val), path);
1324  DEBUG (" %s", data->str);
1325  break;
1326  }
1327  case KVP_TYPE_FRAME:
1328  {
1329  path = g_strjoin ("/", data->full_kvp_path, key, NULL);
1330  g_free (data->full_kvp_path);
1331  data->full_kvp_path = path;
1333  kvpvalue_to_sql_update, data);
1334  break;
1335  }
1336  default:
1337  {
1338  PERR (" unsupported value = %d", kvp_value_get_type (val));
1339  break;
1340  }
1341  }
1342  LEAVE (" %s", data->str);
1343 }
1344 
1345 gchar *
1347 {
1348  gchar * sql_str, * start;
1349  eas data;
1350 
1351  if (!kvp_table_name)
1352  kvp_table_name = g_strdup(QSQL_KVP_TABLE);
1353  ENTER ("create table for %s", obj->e_type);
1354  start = g_strdup_printf ("CREATE TABLE %s (", obj->e_type);
1355  data.ent = NULL;
1356  data.str = g_strdup("");
1357  data.kvp_str = g_strdup("");
1358  qof_class_param_foreach (obj->e_type, string_param_foreach, &data);
1359  sql_str = g_strjoin ("", start, data.str, END_DB_VERSION, data.kvp_str, NULL);
1360  g_free (start);
1361  g_free (data.kvp_str);
1362  g_free (data.str);
1363  LEAVE ("sql_str=%s", sql_str);
1364  return sql_str;
1365 }
1366 
1367 gchar *
1369 {
1370  gchar * sql_str, * start;
1371  eas data;
1372 
1373  g_return_val_if_fail (ent, NULL);
1374  if (!kvp_table_name)
1375  kvp_table_name = g_strdup(QSQL_KVP_TABLE);
1376  ENTER ("create table for %s", ent->e_type);
1377  start = g_strdup_printf ("CREATE TABLE %s (", ent->e_type);
1378  data.ent = ent;
1379  data.str = g_strdup("");
1380  data.kvp_str = g_strdup("");
1381  qof_class_param_foreach (ent->e_type, string_param_foreach, &data);
1382  sql_str = g_strjoin ("", start, data.str, END_DB_VERSION, data.kvp_str, NULL);
1383  g_free (start);
1384  LEAVE ("sql_str=%s", sql_str);
1385  return sql_str;
1386 }
1387 
1388 gchar *
1390 {
1391  KvpFrame * slots;
1392  eas data;
1393  gchar * command, * fields, * values, *id, *gstr, *sql_str, *kvp;
1394 
1395  data.ent = ent;
1396  data.str = g_strdup("");
1397  if (!kvp_table_name)
1398  kvp_table_name = g_strdup(QSQL_KVP_TABLE);
1399  ENTER (" insert a single '%s'", ent->e_type);
1400  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1402  DEBUG (" guid=%s", gstr);
1403  command = g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
1404  // store param list in fields
1405  qof_class_param_foreach (ent->e_type, create_param_list, &data);
1406  fields = g_strdup(data.str);
1407  // store param values in values
1408  g_free (data.str);
1409  data.str = g_strdup("");
1410  data.full_kvp_path = g_strdup("");
1411  qof_class_param_foreach (ent->e_type, create_sql_from_param_cb, &data);
1412  values = data.str;
1413  /* handle KVP */
1414  kvp = g_strdup("");
1415  slots = qof_instance_get_slots ((QofInstance *) ent);
1416  if (!kvp_frame_is_empty(slots))
1417  {
1418  id = g_strdup_printf ("%lu", kvp_id);
1419  g_free (kvp);
1421  kvp = g_strconcat (" INSERT into ", kvp_table_name,
1422  " (kvp_id, guid, type, path, value) VALUES ('", id, "', '",
1423  gstr, "', ", data.str, ");", NULL);
1424  /* increment the index value of the KVP table */
1425  kvp_id++;
1426  g_free (data.str);
1427  }
1428  sql_str = g_strjoin ("", command, fields, ") VALUES ('", gstr, "' ",
1429  values, ");", kvp, NULL);
1430  g_free (command);
1431  g_free (fields);
1432  g_free (gstr);
1433  g_free (values);
1434  g_free (data.full_kvp_path);
1435  LEAVE ("sql_str=%s", sql_str);
1436  return sql_str;
1437 }
1438 
1439 static void
1440 collect_kvp (QofEntity * ent, gpointer user_data)
1441 {
1442  KvpFrame * slots;
1443  KvpValue * collguid;
1444  gchar * gstr, * name, * key;
1445  const QofParam * G_GNUC_UNUSED param;
1446 
1447  name = (gchar *) user_data;
1448  param = qof_class_get_parameter (ent->e_type, name);
1449  key = g_strconcat ("collection/", name, "/guid/", NULL);
1450  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1452  collguid = kvp_value_new_string(gstr);
1453  slots = qof_instance_get_slots((QofInstance*)ent);
1454  kvp_frame_set_value (slots, key, collguid);
1455  g_free (key);
1456  g_free (gstr);
1457 }
1458 
1459 gchar *
1461 {
1462  gchar *gstr, * sql_str, * param_str;
1463  QofInstance * inst;
1464  const QofParam * param;
1465  inst = (QofInstance*)ent;
1466 
1467  if (!inst->param)
1468  return NULL;
1469  ENTER (" modified %s param:%s", ent->e_type, inst->param->param_name);
1470  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1472  param = inst->param;
1473  if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT))
1474  {
1475  gchar * name;
1476  QofCollection * coll;
1477 
1478  coll = param->param_getfcn (ent, param);
1479  name = g_strdup (param->param_name);
1480  qof_collection_foreach (coll, collect_kvp, name);
1481  g_free (name);
1482  return NULL;
1483  }
1484  param_str = qof_util_param_to_string (ent, inst->param);
1485  if (param_str)
1486  g_strescape (param_str, NULL);
1487  sql_str = g_strconcat ("UPDATE ", ent->e_type, " SET ",
1488  inst->param->param_name, " = '", param_str,
1489  "' WHERE ", QOF_TYPE_GUID, "='", gstr, "';", NULL);
1490  LEAVE ("sql_str=%s", sql_str);
1491  return sql_str;
1492 }
1493 
1494 gchar *
1496 {
1497  eas data;
1498  gchar *gstr, * sql_str;
1499  QofInstance * inst;
1500  gchar * start;
1501  KvpFrame * slots;
1502  inst = (QofInstance*)ent;
1503 
1504  if (!inst->param)
1505  return NULL;
1506  sql_str = NULL;
1508  return NULL;
1509 
1510  ENTER (" modified %s param:%s", ent->e_type, inst->param->param_name);
1511  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1513  data.str = g_strdup("");
1514  data.full_kvp_path = g_strdup("");
1515  slots = qof_instance_get_slots ((QofInstance*)ent);
1516  start = g_strjoin ("", "UPDATE ", kvp_table_name, " SET ", NULL);
1520  sql_str = g_strjoin ("", start, data.str, " guid='", gstr, "';", NULL);
1521  g_free (start);
1522  g_free (data.full_kvp_path);
1523  g_free (data.str);
1524  LEAVE ("sql_str=%s", sql_str);
1525  return sql_str;
1526 }
1527 
1528 gchar *
1529 qof_sql_entity_update_list (QofEntity * ent, GList **params)
1530 {
1531  return NULL;
1532 }
1533 
1534 gchar *
1536 {
1537  gchar * gstr, * sql_str;
1538  ENTER (" %s", ent->e_type);
1539  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
1541  sql_str = g_strconcat ("DELETE from ", ent->e_type, " WHERE ",
1542  QOF_TYPE_GUID, "='", gstr, "';", "DELETE from ", kvp_table_name,
1543  " WHERE kvp_id ", "='", gstr, "';", NULL);
1544  g_free (gstr);
1545  return sql_str;
1546 }
1547 
1548 gchar *
1550 {
1551  gchar * sql_str;
1552  ENTER (" drop table for '%s'", ent->e_type);
1553  sql_str = g_strdup_printf ("DROP TABLE %s;", ent->e_type);
1554  LEAVE ("sql_str=%s", sql_str);
1555  return sql_str;
1556 }
1557 
1558 void qof_sql_entity_set_kvp_tablename (const gchar * name)
1559 {
1560  g_return_if_fail (name);
1561  kvp_table_name = g_strdup(name);
1562 }
1563 
1565 {
1566  kvp_id = id;
1567 }
1568 
1570 {
1571  return kvp_id;
1572 }
1573 
1574 void qof_sql_entity_set_kvp_exists (gboolean exist)
1575 {
1576  kvp_table_exists = exist;
1577 }
1578 
1579 /* ========================== END OF FILE =================== */
const gchar * qof_util_whitespace_filter(const gchar *val)
Definition: qofutil.c:234
#define QOF_DATE_FORMAT_UTC
QOF UTC format, xsd:date compatible. QOF_UTC_DATE_FORMAT "%Y-%m-%dT%H:%M:%SZ".
Definition: qofdate.h:277
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:73
#define PERR(format, args...)
Definition: qoflog.h:183
gpointer qof_object_new_instance(QofIdTypeConst type_name, QofBook *book)
Definition: qofobject.c:42
QofQueryPredData * qof_query_kvp_predicate_path(QofQueryCompare how, const gchar *path, const KvpValue *value)
#define QOF_TYPE_COLLECT
secondary collections are used for one-to-many references between entities and are implemented using ...
Definition: qofclass.h:121
const gchar * QofIdType
Definition: qofid.h:81
#define QSQL_KVP_TABLE
Definition: qof-sqlite.c:55
#define PINFO(format, args...)
Definition: qoflog.h:199
void qof_sql_query_parse(QofSqlQuery *query, const gchar *str)
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:133
struct _QofNumeric QofNumeric
A rational-number type.
Definition: qofnumeric.h:61
void qof_date_free(QofDate *date)
Definition: qofdate.c:642
void qof_class_param_foreach(QofIdTypeConst obj_name, QofParamForeachCB cb, gpointer user_data)
Definition: qofclass.c:268
gchar * qof_sql_entity_insert(QofEntity *ent)
Build a SQL &#39;INSERT&#39; statement for this entity.
Definition: qofsql.c:1389
KvpValueType
possible types in the union KvpValue
Definition: kvpframe.h:87
gboolean string_to_guid(const gchar *string, GUID *guid)
Unique identifier.
Definition: kvpframe.h:118
gchar * qof_sql_object_create_table(QofObject *obj)
Build a SQL &#39;CREATE&#39; statement for this object.
Definition: qofsql.c:1346
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
void qof_sql_query_set_book(QofSqlQuery *q, QofBook *book)
Definition: qofsql.c:113
static void kvpvalue_to_sql_update(const gchar *key, KvpValue *val, gpointer user_data)
Definition: qofsql.c:1300
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level)
Definition: qoflog.c:204
void qof_sql_entity_set_kvp_id(gulong id)
Set the initial index value of the KVP table.
Definition: qofsql.c:1564
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:252
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
Definition: qofquery.c:1282
gulong qof_sql_entity_get_kvp_id(void)
Get the index value of the KVP table after the operation(s).
Definition: qofsql.c:1569
gboolean kvp_frame_is_empty(KvpFrame *frame)
Definition: kvpframe.c:134
QofBook * qof_instance_get_book(QofInstance *inst)
Definition: qofinstance.c:87
#define LEAVE(format, args...)
Definition: qoflog.h:227
#define GUID_ENCODING_LENGTH
Definition: guid.h:64
struct _QofQuery QofQuery
Definition: qofquery.h:85
QofTime * qof_date_to_qtime(const QofDate *qd)
Definition: qofdate.c:926
Full range replacement for struct tm.
Definition: qofdate.h:138
KvpFrame * kvp_frame_set_value(KvpFrame *frame, const gchar *key_path, const KvpValue *value)
Copy the KvpValue into the frame.
Definition: kvpframe.c:496
128bit denominator/numerator maths.
Definition: kvpframe.h:106
gchar * qof_sql_entity_update(QofEntity *ent)
Build a SQL &#39;UPDATE&#39; statement for the current entity parameter.
Definition: qofsql.c:1460
gint64 kvp_value_get_gint64(const KvpValue *value)
Definition: kvpframe.c:1399
gchar * qof_sql_entity_create_table(QofEntity *ent)
Build a SQL &#39;CREATE&#39; statement for this entity.
Definition: qofsql.c:1368
struct QofCollection_s QofCollection
Definition: qofid.h:138
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const gchar *parameter)
Definition: qofclass.c:147
const GUID * qof_instance_get_guid(QofInstance *inst)
Definition: qofinstance.c:79
QofDate * qof_date_parse(const gchar *str, QofDateFormat df)
Convert a timestamp to a QofTime.
Definition: qofdate.c:557
struct _KvpValue KvpValue
Definition: kvpframe.h:78
void qof_query_destroy(QofQuery *q)
Definition: qofquery.c:998
KvpFrame * qof_instance_get_slots(QofInstance *inst)
Definition: qofinstance.c:95
gchar * qof_sql_entity_update_list(QofEntity *ent, GList **params)
Build a SQL &#39;UPDATE&#39; statement for a list of parameters.
Definition: qofsql.c:1529
QofGuidMatch
Definition: qofquerycore.h:104
static gchar * string_param_to_sql(QofParam *param)
Definition: qofsql.c:1134
gboolean qof_numeric_from_string(const gchar *str, QofNumeric *n)
Definition: qofnumeric.c:1116
QofQuery * qof_sql_query_get_query(QofSqlQuery *q)
Definition: qofsql.c:103
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:392
void qof_query_add_term(QofQuery *q, GSList *param_list, QofQueryPredData *pred_data, QofQueryOp op)
Definition: qofquery.c:691
64bit integer
Definition: kvpframe.h:94
void qof_sql_query_set_kvp(QofSqlQuery *q, KvpFrame *kvp)
Definition: qofsql.c:123
static gchar * kvp_table_name
Definition: qofsql.c:51
#define DEBUG(format, args...)
Definition: qoflog.h:208
void qof_query_set_book(QofQuery *q, QofBook *book)
Definition: qofquery.c:1335
void qof_query_set_sort_order(QofQuery *q, GSList *params1, GSList *params2, GSList *params3)
Definition: qofquery.c:1247
gchar * qof_util_param_to_string(QofEntity *ent, const QofParam *param)
Converts a parameter to a string for storage or display.
Definition: qofutil.c:464
static void create_param_list(QofParam *param, gpointer user_data)
list just the parameter names
Definition: qofsql.c:1220
gchar * guid_to_string_buff(const GUID *guid, gchar *buff)
void qof_sql_entity_set_kvp_exists(gboolean exist)
Set or clear a flag that the KVP table exists or not.
Definition: qofsql.c:1574
gchar * kvp_value_to_bare_string(const KvpValue *val)
General purpose function to convert any KvpValue to a string.
Definition: kvpframe.c:1834
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Definition: qofquery.c:1127
QofQueryCompare
Definition: qofquerycore.h:51
gchar * kvp_value_get_string(const KvpValue *value)
Definition: kvpframe.c:1444
Private QOF SQL generation routines.
QofCharMatch
Definition: qofquerycore.h:127
QofEntity entity
Definition: qofinstance-p.h:39
QofSqlQuery * qof_sql_query_new(void)
Definition: qofsql.c:75
const gchar * QofType
Definition: qofclass.h:125
GList * qof_class_get_referenceList(QofIdTypeConst type)
List of the parameters that could be references.
Definition: qofclass.c:329
gchar * qof_sql_entity_update_kvp(QofEntity *ent)
Build a SQL &#39;UPDATE&#39; statement for the KVP data in this entity.
Definition: qofsql.c:1495
QofQuery * qof_query_invert(QofQuery *q)
Definition: qofquery.c:1043
gchar * qof_sql_entity_drop_table(QofEntity *ent)
Build a SQL &#39;DROP&#39; statement for this entity type.
Definition: qofsql.c:1549
void kvp_frame_for_each_slot(KvpFrame *f, KvpValueForeachCB proc, gpointer data)
Definition: kvpframe.c:1642
Definition: guid.h:53
void qof_sql_entity_set_kvp_tablename(const gchar *name)
Set a default KVP table name for each backend.
Definition: qofsql.c:1558
QofQueryOp
Definition: qofquery.h:88
GList * qof_query_run(QofQuery *q)
Definition: qofquery.c:757
const gchar * QofIdTypeConst
Definition: qofid.h:83
#define PWARN(format, args...)
Definition: qoflog.h:191
struct QofTime64 QofTime
Use a 64-bit signed int QofTime.
Definition: qoftime.h:112
Simple boolean type.
Definition: kvpframe.h:136
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
QofType qof_class_get_parameter_type(QofIdTypeConst obj_name, const gchar *param_name)
Definition: qofclass.c:199
QofBackend * qof_book_get_backend(QofBook *book)
Retrieve the backend used by this book.
Definition: qofbook.c:154
standard C string
Definition: kvpframe.h:112
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:75
KvpFrame * kvp_value_get_frame(const KvpValue *value)
Definition: kvpframe.c:1546
const QofParam * param
Definition: qofinstance-p.h:53
standard C double type
Definition: kvpframe.h:100
GList * qof_sql_query_run(QofSqlQuery *query, const gchar *str)
Perform the query, return the results.
struct ent_and_string eas
#define ENTER(format, args...)
Definition: qoflog.h:217
gchar * qof_sql_entity_delete(QofEntity *ent)
Build a SQL &#39;DELETE&#39; statement for this entity.
Definition: qofsql.c:1535
QofQuery * qof_query_create(void)
Definition: qofquery.c:900
const gchar * QofLogModule
Definition: qofid.h:85
#define QOF_QUERY_FIRST_TERM
Definition: qofquery.h:98
64bit time/date handling.
Definition: kvpframe.h:124
void qof_query_search_for(QofQuery *q, QofIdTypeConst obj_type)
Definition: qofquery.c:909
GList * qof_sql_query_rerun(QofSqlQuery *query)
Definition: qofsql.c:1044
static void kvpvalue_to_sql_insert(const gchar *key, KvpValue *val, gpointer user_data)
Definition: qofsql.c:1252