QOF  0.7.5
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 
30 #include "config.h"
31 #include <stdlib.h> /* for working atoll */
32 #include <errno.h>
33 #include <glib.h>
34 #include <libintl.h>
35 #ifdef HAVE_GDA
36 #include <libsql/sql_parser.h>
37 #else
38 #include "sql_parser.h"
39 #endif
40 #include <time.h>
41 #include "qof.h"
42 #include "qofquery-p.h"
43 
44 #define _(String) dgettext (GETTEXT_PACKAGE, String)
45 
46 static QofLogModule log_module = QOF_MOD_QUERY;
47 
48 /* =================================================================== */
49 
50 struct _QofSqlQuery
51 {
52  sql_statement *parse_result;
53  QofQuery *qof_query;
54  QofBook *book;
55  gchar *single_global_tablename;
56  KvpFrame *kvp_join;
57  GList *param_list;
58  QofEntity *inserted_entity;
59 };
60 
61 /* ========================================================== */
62 
63 QofSqlQuery *
65 {
66  QofSqlQuery *sqn = (QofSqlQuery *) g_new0 (QofSqlQuery, 1);
67 
68  sqn->qof_query = NULL;
69  sqn->parse_result = NULL;
70  sqn->book = NULL;
71  sqn->single_global_tablename = NULL;
72  sqn->kvp_join = NULL;
73 
74  return sqn;
75 }
76 
77 /* ========================================================== */
78 
79 void
80 qof_sql_query_destroy (QofSqlQuery * q)
81 {
82  if (!q)
83  return;
84  qof_query_destroy (q->qof_query);
85  sql_destroy (q->parse_result);
86  g_free (q);
87 }
88 
89 /* ========================================================== */
90 
91 QofQuery *
92 qof_sql_query_get_query (QofSqlQuery * q)
93 {
94  if (!q)
95  return NULL;
96  return q->qof_query;
97 }
98 
99 /* ========================================================== */
100 
101 void
102 qof_sql_query_set_book (QofSqlQuery * q, QofBook * book)
103 {
104  if (!q)
105  return;
106  q->book = book;
107 }
108 
109 /* ========================================================== */
110 
111 void
112 qof_sql_query_set_kvp (QofSqlQuery * q, KvpFrame * kvp)
113 {
114  if (!q)
115  return;
116  q->kvp_join = kvp;
117 }
118 
119 /* ========================================================== */
120 
121 static inline void
122 get_table_and_param (char *str, char **tab, char **param)
123 {
124  char *end = strchr (str, '.');
125  if (!end)
126  {
127  *tab = 0;
128  *param = str;
129  return;
130  }
131  *end = 0;
132  *tab = str;
133  *param = end + 1;
134 }
135 
136 static inline char *
137 dequote_string (char *str)
138 {
139  size_t len;
140  /* strip out quotation marks ... */
141  if (('\'' == str[0]) || ('\"' == str[0]))
142  {
143  str++;
144  len = strlen (str);
145  str[len - 1] = 0;
146  }
147  return str;
148 }
149 
150 static QofQuery *
151 handle_single_condition (QofSqlQuery * query, sql_condition * cond)
152 {
153  char tmpbuff[128];
154  GSList *param_list;
155  GList *guid_list;
156  QofQueryPredData *pred_data;
157  sql_field_item *sparam, *svalue;
158  gchar *qparam_name, *qvalue_name, *table_name, *param_name;
159  gchar *sep, *path, *str, *p;
160  QofQuery *qq;
161  KvpValue *kv, *kval;
162  KvpValueType kvt;
163  QofQueryCompare qop;
164  guint len;
165  QofType param_type;
166  QofGuidMatch gm;
167 
168  pred_data = NULL;
169  if (NULL == cond)
170  {
171  PWARN ("missing condition");
172  return NULL;
173  }
174  /* -------------------------------- */
175  /* field to match, assumed, for now to be on the left */
176  /* XXX fix this so it can be either left or right */
177  if (NULL == cond->d.pair.left)
178  {
179  PWARN ("missing left parameter");
180  return NULL;
181  }
182  sparam = cond->d.pair.left->item;
183  if (SQL_name != sparam->type)
184  {
185  PWARN ("we support only parameter names at this time (parsed %d)",
186  sparam->type);
187  return NULL;
188  }
189  qparam_name = sparam->d.name->data;
190  if (NULL == qparam_name)
191  {
192  PWARN ("missing parameter name");
193  return NULL;
194  }
195 
196  /* -------------------------------- */
197  /* value to match, assumed, for now, to be on the right. */
198  /* XXX fix this so it can be either left or right */
199  if (NULL == cond->d.pair.right)
200  {
201  PWARN ("missing right parameter");
202  return NULL;
203  }
204  svalue = cond->d.pair.right->item;
205  if (SQL_name != svalue->type)
206  {
207  PWARN ("we support only simple values (parsed as %d)",
208  svalue->type);
209  return NULL;
210  }
211  qvalue_name = svalue->d.name->data;
212  if (NULL == qvalue_name)
213  {
214  PWARN ("missing value");
215  return NULL;
216  }
217  qvalue_name = dequote_string (qvalue_name);
218  qvalue_name = (char *) qof_util_whitespace_filter (qvalue_name);
219 
220  /* Look to see if its the special KVP value holder.
221  * If it is, look up the value. */
222  if (0 == strncasecmp (qvalue_name, "kvp://", 6))
223  {
224  if (NULL == query->kvp_join)
225  {
226  PWARN ("missing kvp frame");
227  return NULL;
228  }
229  kv = kvp_frame_get_value (query->kvp_join, qvalue_name + 5);
230  /* If there's no value, its not an error;
231  * we just don't do this predicate */
232  if (!kv)
233  return NULL;
234  kvt = kvp_value_get_type (kv);
235 
236  tmpbuff[0] = 0x0;
237  qvalue_name = tmpbuff;
238  switch (kvt)
239  {
240  case KVP_TYPE_GINT64:
241  {
242  gint64 ival = kvp_value_get_gint64 (kv);
243  sprintf (tmpbuff, "%" G_GINT64_FORMAT "\n", ival);
244  break;
245  }
246  case KVP_TYPE_DOUBLE:
247  {
248  double ival = kvp_value_get_double (kv);
249  sprintf (tmpbuff, "%26.18g\n", ival);
250  break;
251  }
252  case KVP_TYPE_STRING:
253  /* If there's no value, its not an error;
254  * we just don't do this predicate */
255  qvalue_name = kvp_value_get_string (kv);
256  if (!qvalue_name)
257  return NULL;
258  break;
259  case KVP_TYPE_GUID:
260  case KVP_TYPE_TIME :
261 #ifndef QOF_DISABLE_DEPRECATED
262  case KVP_TYPE_TIMESPEC:
263 #endif
264  case KVP_TYPE_BOOLEAN :
265  case KVP_TYPE_BINARY:
266  case KVP_TYPE_GLIST:
267  case KVP_TYPE_NUMERIC:
268  case KVP_TYPE_FRAME:
269  PWARN ("unhandled kvp type=%d", kvt);
270  return NULL;
271  }
272  }
273 
274  /* -------------------------------- */
275  /* Now start building the QOF parameter */
276  param_list = qof_query_build_param_list (qparam_name, NULL);
277 
278  /* Get the where-term comparison operator */
279  switch (cond->op)
280  {
281  case SQL_eq:
282  qop = QOF_COMPARE_EQUAL;
283  break;
284  case SQL_gt:
285  qop = QOF_COMPARE_GT;
286  break;
287  case SQL_lt:
288  qop = QOF_COMPARE_LT;
289  break;
290  case SQL_geq:
291  qop = QOF_COMPARE_GTE;
292  break;
293  case SQL_leq:
294  qop = QOF_COMPARE_LTE;
295  break;
296  case SQL_diff:
297  qop = QOF_COMPARE_NEQ;
298  break;
299  default:
300  /* XXX for string-type queries, we should be able to
301  * support 'IN' for substring search. Also regex. */
302  PWARN ("Unsupported compare op (parsed as %u)", cond->op);
303  return NULL;
304  }
305 
306  /* OK, need to know the type of the thing being matched
307  * in order to build the correct predicate. Get the type
308  * from the object parameters. */
309  get_table_and_param (qparam_name, &table_name, &param_name);
310  if (NULL == table_name)
311  {
312  table_name = query->single_global_tablename;
313  }
314  if (NULL == table_name)
315  {
316  PWARN ("Need to specify an object class to query");
317  return NULL;
318  }
319 
320  if (FALSE == qof_class_is_registered (table_name))
321  {
322  PWARN ("The query object \'%s\' is not known", table_name);
323  return NULL;
324  }
325 
326  param_type = qof_class_get_parameter_type (table_name, param_name);
327  if (!param_type)
328  {
329  PWARN ("The parameter \'%s\' on object \'%s\' is not known",
330  param_name, table_name);
331  return NULL;
332  }
333 
334  if (!strcmp (param_type, QOF_TYPE_STRING))
335  {
336  pred_data = qof_query_string_predicate (qop, /* comparison to make */
337  qvalue_name, /* string to match */
338  QOF_STRING_MATCH_CASEINSENSITIVE, /* case matching */
339  FALSE); /* use_regexp */
340  }
341  else if (!strcmp (param_type, QOF_TYPE_CHAR))
342  {
343  QofCharMatch cm = QOF_CHAR_MATCH_ANY;
344  if (QOF_COMPARE_NEQ == qop)
345  cm = QOF_CHAR_MATCH_NONE;
346  pred_data = qof_query_char_predicate (cm, qvalue_name);
347  }
348  else if (!strcmp (param_type, QOF_TYPE_INT32))
349  {
350  gint32 ival = atoi (qvalue_name);
351  pred_data = qof_query_int32_predicate (qop, ival);
352  }
353  else if (!strcmp (param_type, QOF_TYPE_INT64))
354  {
355  gint64 ival = atoll (qvalue_name);
356  pred_data = qof_query_int64_predicate (qop, ival);
357  }
358  else if (!strcmp (param_type, QOF_TYPE_DOUBLE))
359  {
360  double ival = atof (qvalue_name);
361  pred_data = qof_query_double_predicate (qop, ival);
362  }
363  else if (!strcmp (param_type, QOF_TYPE_BOOLEAN))
364  {
365  gboolean ival = qof_util_bool_to_int (qvalue_name);
366  pred_data = qof_query_boolean_predicate (qop, ival);
367  }
368  else if (!safe_strcmp (param_type, QOF_TYPE_TIME))
369  {
370  QofDate *qd;
371  QofTime *qt;
372 
373  qd = qof_date_parse (qvalue_name, QOF_DATE_FORMAT_UTC);
374  qt = qof_date_to_qtime (qd);
375  qof_date_free (qd);
376  pred_data =
377  qof_query_time_predicate (qop, QOF_DATE_MATCH_NORMAL,
378  qt);
379  }
380 #ifndef QOF_DISABLE_DEPRECATED
381  else if (!strcmp (param_type, QOF_TYPE_DATE))
382  {
383  gint rc;
384  Timespec ts;
385  time_t exact;
386 
387  /* Use a timezone independent setting */
388  qof_date_format_set (QOF_DATE_FORMAT_UTC);
389  rc = 0;
390  if (FALSE == qof_scan_date_secs (qvalue_name, &exact))
391  {
392  char *tail;
393  exact = strtoll (qvalue_name, &tail, 0);
394 // PWARN ("unable to parse date: %s", qvalue_name);
395 // return NULL;
396  }
397  ts.tv_sec = exact;
398  ts.tv_nsec = 0;
399  pred_data =
400  qof_query_date_predicate (qop, QOF_DATE_MATCH_NORMAL, ts);
401  }
402 #endif
403  else if (!strcmp (param_type, QOF_TYPE_NUMERIC))
404  {
405  QofNumeric ival;
406  qof_numeric_from_string (qvalue_name, &ival);
407  pred_data =
408  qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
409  }
410  else if (!strcmp (param_type, QOF_TYPE_DEBCRED))
411  {
412  /* DEBCRED is likely to be deprecated before libqof2 */
413  QofNumeric ival;
414  qof_numeric_from_string (qvalue_name, &ival);
415  pred_data =
416  qof_query_numeric_predicate (qop, QOF_NUMERIC_MATCH_ANY, ival);
417  }
418  else if (!strcmp (param_type, QOF_TYPE_GUID))
419  {
420  GUID guid;
421  gboolean rc = string_to_guid (qvalue_name, &guid);
422  if (0 == rc)
423  {
424  PWARN ("unable to parse guid: %s", qvalue_name);
425  return NULL;
426  }
427 
428  // XXX less, than greater than don't make sense,
429  // should check for those bad conditions
430 
431  gm = QOF_GUID_MATCH_ANY;
432  if (QOF_COMPARE_NEQ == qop)
433  gm = QOF_GUID_MATCH_NONE;
434  guid_list = g_list_append (NULL, &guid);
435  pred_data = qof_query_guid_predicate (gm, guid_list);
436 
437  g_list_free (guid_list);
438  }
439  else if (!strcmp (param_type, QOF_TYPE_KVP))
440  {
441  /* We are expecting an encoded value that looks like
442  * /some/path/string:value
443  */
444  sep = strchr (qvalue_name, ':');
445  if (!sep)
446  return NULL;
447  *sep = 0;
448  path = qvalue_name;
449  str = sep + 1;
450  /* If str has only digits, we know its a plain number.
451  * If its numbers and a decimal point, assume a float
452  * If its numbers and a slash, assume numeric
453  * If its 32 bytes of hex, assume GUID
454  * If it looks like an iso date ...
455  * else assume its a string.
456  */
457  kval = NULL;
458  len = strlen (str);
459  if ((32 == len) && (32 == strspn (str, "0123456789abcdef")))
460  {
461  GUID guid;
462  string_to_guid (str, &guid);
463  kval = kvp_value_new_guid (&guid);
464  }
465  else if (len == strspn (str, "0123456789"))
466  {
467  kval = kvp_value_new_gint64 (atoll (str));
468  }
469  else if ((p = strchr (str, '.')) &&
470  ((len - 1) == (strspn (str, "0123456789") +
471  strspn (p + 1, "0123456789"))))
472  {
473  kval = kvp_value_new_double (atof (str));
474  }
475 
476  else if ((p = strchr (str, '/')) &&
477  ((len - 1) == (strspn (str, "0123456789") +
478  strspn (p + 1, "0123456789"))))
479  {
480  QofNumeric num;
481  qof_numeric_from_string (str, &num);
482  kval = kvp_value_new_numeric (num);
483  }
484  else if ((p = strchr (str, '-')) &&
485  (p = strchr (p + 1, '-')) &&
486  (p = strchr (p + 1, ' ')) &&
487  (p = strchr (p + 1, ':')) && (p = strchr (p + 1, ':')))
488  {
489  QofDate *qd;
490  QofTime *qt;
491 
493  qt = qof_date_to_qtime (qd);
494  kval =
495  kvp_value_new_time (qt);
496  qof_date_free (qd);
497  }
498 
499  /* The default handler is a string */
500  if (NULL == kval)
501  {
502  kval = kvp_value_new_string (str);
503  }
504  pred_data = qof_query_kvp_predicate_path (qop, path, kval);
505  }
506  else
507  {
508  PWARN ("The predicate type \"%s\" is unsupported for now",
509  param_type);
510  return NULL;
511  }
512 
513  qq = qof_query_create ();
514  qof_query_add_term (qq, param_list, pred_data, QOF_QUERY_FIRST_TERM);
515  return qq;
516 }
517 
518 /* ========================================================== */
519 
520 static QofQuery *
521 handle_where (QofSqlQuery * query, sql_where * swear)
522 {
523  QofQueryOp qop;
524  QofQuery *qq;
525 
526  switch (swear->type)
527  {
528  case SQL_pair:
529  {
530  QofQuery *qleft = handle_where (query, swear->d.pair.left);
531  QofQuery *qright = handle_where (query, swear->d.pair.right);
532  if (NULL == qleft)
533  return qright;
534  if (NULL == qright)
535  return qleft;
536  switch (swear->d.pair.op)
537  {
538  case SQL_and:
539  qop = QOF_QUERY_AND;
540  break;
541  case SQL_or:
542  qop = QOF_QUERY_OR;
543  break;
544  /* XXX should add support for nand, nor, xor */
545  default:
546  qof_query_destroy (qleft);
547  qof_query_destroy (qright);
548  return NULL;
549  }
550  qq = qof_query_merge (qleft, qright, qop);
551  qof_query_destroy (qleft);
552  qof_query_destroy (qright);
553  return qq;
554  }
555  case SQL_negated:
556  {
557  QofQuery *qq = handle_where (query, swear->d.negated);
558  QofQuery *qneg = qof_query_invert (qq);
559  qof_query_destroy (qq);
560  return qneg;
561  }
562 
563  case SQL_single:
564  {
565  sql_condition *cond = swear->d.single;
566  return handle_single_condition (query, cond);
567  }
568  }
569  return NULL;
570 }
571 
572 /* ========================================================== */
573 
574 static void
575 handle_sort_order (QofSqlQuery * query, GList * sorder_list)
576 {
577  GSList *qsp[3];
578  GList *n;
579  gboolean direction[3];
580  int i;
581  sql_order_field *sorder;
582  char *qparam_name;
583 
584  if (!sorder_list)
585  return;
586 
587  for (i = 0; i < 3; i++)
588  {
589  qsp[i] = NULL;
590  direction[i] = 0;
591 
592  if (sorder_list)
593  {
594  sorder = sorder_list->data;
595 
596  /* Set the sort direction */
597  if (SQL_asc == sorder->order_type)
598  direction[i] = TRUE;
599 
600  /* Find the parameter name */
601  qparam_name = NULL;
602  n = sorder->name;
603  if (n)
604  {
605  qparam_name = n->data;
606  if (qparam_name)
607  {
608  qsp[i] =
609  qof_query_build_param_list (qparam_name, NULL);
610  }
611  n = n->next; /* next parameter */
612  }
613  else
614  {
615  /* if no next parameter, then next order-by */
616  sorder_list = sorder_list->next;
617  }
618  }
619  }
620 
621  qof_query_set_sort_order (query->qof_query, qsp[0], qsp[1], qsp[2]);
622  qof_query_set_sort_increasing (query->qof_query, direction[0],
623  direction[1], direction[2]);
624 }
625 
626 /* INSERT INTO handlers =================================================== */
627 
628 static void
629 qof_sql_insertCB (const QofParam * param, const gchar * insert_string,
630  QofSqlQuery * query)
631 {
632  QofIdTypeConst type;
633  sql_insert_statement *sis;
634  gboolean registered_type;
635  QofEntity *ent;
636  /* cm_ prefix used for variables that hold the data to commit */
637  QofNumeric cm_numeric;
638  gdouble cm_double;
639  gboolean cm_boolean;
640  gint32 cm_i32;
641  gint64 cm_i64;
642  gchar cm_char, *tail;
643  GUID *cm_guid;
644 /* KvpFrame *cm_kvp;
645  KvpValue *cm_value;
646  KvpValueType cm_type;*/
647  void (*string_setter) (QofEntity *, const gchar *);
648  void (*time_setter) (QofEntity *, QofTime *);
649  void (*numeric_setter) (QofEntity *, QofNumeric);
650  void (*double_setter) (QofEntity *, gdouble);
651  void (*boolean_setter) (QofEntity *, gboolean);
652  void (*i32_setter) (QofEntity *, gint32);
653  void (*i64_setter) (QofEntity *, gint64);
654  void (*char_setter) (QofEntity *, gchar);
655 /* void (*kvp_frame_setter) (QofEntity*, KvpFrame*);*/
656 
657  g_return_if_fail (param || insert_string || query);
658  ent = query->inserted_entity;
659  sis = query->parse_result->statement;
660  type = g_strdup_printf ("%s", sis->table->d.simple);
661 
662  ENTER (" param=%s param_type=%s type=%s content=%s",
663  param->param_name, param->param_type, type, insert_string);
664  if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0)
665  {
666  string_setter =
667  (void (*)(QofEntity *, const char *)) param->param_setfcn;
668  if (string_setter != NULL)
669  {
670  string_setter (ent, insert_string);
671  }
672  registered_type = TRUE;
673  }
674  if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0)
675  {
676  QofDate *qd;
677  QofTime *qt;
678  time_setter =
679  (void (*)(QofEntity *, QofTime *)) param->param_setfcn;
680  qd = qof_date_parse (insert_string, QOF_DATE_FORMAT_UTC);
681  qt = qof_date_to_qtime (qd);
682  if((time_setter != NULL) && (qof_time_is_valid(qt)))
683  {
684  time_setter (ent, qt);
685  }
686  }
687 #ifndef QOF_DISABLE_DEPRECATED
688  if (safe_strcmp (param->param_type, QOF_TYPE_DATE) == 0)
689  {
690  void (*date_setter) (QofEntity *, Timespec);
691  Timespec cm_date;
692  struct tm query_time;
693  time_t query_time_t;
694 
695  date_setter =
696  (void (*)(QofEntity *, Timespec)) param->param_setfcn;
697  strptime (insert_string, QOF_UTC_DATE_FORMAT, &query_time);
698  query_time_t = mktime (&query_time);
699  timespecFromTime_t (&cm_date, query_time_t);
700  if (date_setter != NULL)
701  {
702  date_setter (ent, cm_date);
703  }
704  }
705 #endif
706  if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) ||
707  (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0))
708  {
709  numeric_setter =
710  (void (*)(QofEntity *, QofNumeric)) param->param_setfcn;
711  qof_numeric_from_string (insert_string, &cm_numeric);
712  if (numeric_setter != NULL)
713  {
714  numeric_setter (ent, cm_numeric);
715  }
716  }
717  if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0)
718  {
719  cm_guid = g_new (GUID, 1);
720  if (TRUE != string_to_guid (insert_string, cm_guid))
721  {
722  LEAVE (" string to guid failed for %s", insert_string);
723  return;
724  }
725 /* reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
726  if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
727  {
728  qof_entity_set_guid(qsf_ent, cm_guid);
729  }
730  else {
731  reference = qof_entity_get_reference_from(qsf_ent, cm_param);
732  if(reference) {
733  params->referenceList = g_list_append(params->referenceList, reference);
734  }
735  }*/
736  }
737  if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0)
738  {
739  errno = 0;
740  cm_i32 = (gint32) strtol (insert_string, &tail, 0);
741  if (errno == 0)
742  {
743  i32_setter =
744  (void (*)(QofEntity *, gint32)) param->param_setfcn;
745  if (i32_setter != NULL)
746  {
747  i32_setter (ent, cm_i32);
748  }
749  }
750  else
751  {
752  QofBackend *backend;
753  QofBook *book;
754 
755  book = qof_instance_get_book ((QofInstance *) ent);
756  backend = qof_book_get_backend (book);
757  qof_error_set_be (backend, qof_error_register
758  (_("When converting SQLite strings into numbers, an "
759  "overflow has been detected. The SQLite database "
760  "'%s' contains invalid data in a field that is meant "
761  "to hold a number."), TRUE));
762  }
763  }
764  if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0)
765  {
766  errno = 0;
767  cm_i64 = strtoll (insert_string, &tail, 0);
768  if (errno == 0)
769  {
770  i64_setter =
771  (void (*)(QofEntity *, gint64)) param->param_setfcn;
772  if (i64_setter != NULL)
773  {
774  i64_setter (ent, cm_i64);
775  }
776  }
777  else
778  {
779  QofBackend *backend;
780  QofBook *book;
781 
782  book = qof_instance_get_book ((QofInstance *) ent);
783  backend = qof_book_get_backend (book);
784  qof_error_set_be (backend, qof_error_register
785  (_("When converting SQLite strings into numbers, an "
786  "overflow has been detected. The SQLite database "
787  "'%s' contains invalid data in a field that is meant "
788  "to hold a number."), TRUE));
789  }
790  }
791  if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0)
792  {
793  errno = 0;
794  cm_double = strtod (insert_string, &tail);
795  if (errno == 0)
796  {
797  double_setter =
798  (void (*)(QofEntity *, double)) param->param_setfcn;
799  if (double_setter != NULL)
800  {
801  double_setter (ent, cm_double);
802  }
803  }
804  }
805  if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0)
806  {
807  gint b;
808  b = qof_util_bool_to_int (insert_string);
809  if (b == 1)
810  {
811  cm_boolean = TRUE;
812  }
813  else
814  {
815  cm_boolean = FALSE;
816  }
817  boolean_setter =
818  (void (*)(QofEntity *, gboolean)) param->param_setfcn;
819  if (boolean_setter != NULL)
820  {
821  boolean_setter (ent, cm_boolean);
822  }
823  }
824  if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0)
825  {
826 
827  }
828  if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0)
829  {
830  cm_char = *insert_string;
831  char_setter = (void (*)(QofEntity *, char)) param->param_setfcn;
832  if (char_setter != NULL)
833  {
834  char_setter (ent, cm_char);
835  }
836  }
837  LEAVE (" ");
838 }
839 
840 static void
841 qof_query_set_insert_table (QofSqlQuery * query)
842 {
843  sql_insert_statement *sis;
844  sql_table *sis_t;
845  sis = query->parse_result->statement;
846  switch (sis->table->type)
847  {
848  case SQL_simple:
849  {
850  sis_t = sis->table;
851  query->single_global_tablename =
852  g_strdup_printf ("%s", sis_t->d.simple);
853  qof_query_search_for (query->qof_query,
854  query->single_global_tablename);
855  PINFO (" insert set to table: %s", sis_t->d.simple);
856  break;
857  }
858  default:
859  {
860  PWARN ("SQL insert only handles simple statements");
861  }
862  }
863 }
864 
865 static QofEntity *
866 qof_query_insert (QofSqlQuery * query)
867 {
868  GList *field_list, *value_list, *cur;
869  const gchar *param_name;
870  gchar *value;
871  QofIdType type;
872  const QofParam *param;
873  QofInstance *inst;
874  sql_insert_statement *sis;
875  sql_field *field;
876  sql_field_item *item;
877 
878  ENTER (" ");
879  query->param_list = NULL;
880  type = NULL;
881  param = NULL;
882  value = NULL;
883  field_list = NULL;
884  value_list = NULL;
885  param_name = NULL;
886  sis = query->parse_result->statement;
887  if (!sis->fields || !sis->values)
888  {
889  LEAVE (" NULL insert statement");
890  return NULL;
891  }
892  type = g_strdup (query->single_global_tablename);
893  inst = (QofInstance *) qof_object_new_instance (type, query->book);
894  if (inst == NULL)
895  {
896  LEAVE (" unable to create instance of type %s", type);
897  return NULL;
898  }
899  query->inserted_entity = &inst->entity;
900  value_list = sis->values;
901  for (field_list = sis->fields; field_list != NULL;
902  field_list = field_list->next)
903  {
904  field = value_list->data;
905  item = field->item;
906  for (cur = item->d.name; cur != NULL; cur = cur->next)
907  {
908  value =
909  g_strdup_printf ("%s",
910  dequote_string ((char *) cur->data));
911  }
912  field = field_list->data;
913  item = field->item;
914  for (cur = item->d.name; cur != NULL; cur = cur->next)
915  {
916  param_name = g_strdup_printf ("%s", (char *) cur->data);
917  param = qof_class_get_parameter (type, param_name);
918  }
919  if (param && value)
920  {
921  qof_sql_insertCB (param, value, query);
922  }
923  value_list = g_list_next (value_list);
924  }
925  LEAVE (" ");
926  return query->inserted_entity;
927 }
928 
929 static const char *
930 sql_type_as_string (sql_statement_type type)
931 {
932  switch (type)
933  {
934  case SQL_select:
935  {
936  return "SELECT";
937  }
938  case SQL_insert:
939  {
940  return "INSERT";
941  }
942  case SQL_delete:
943  {
944  return "DELETE";
945  }
946  case SQL_update:
947  {
948  return "UPDATE";
949  }
950  default:
951  {
952  return "unknown";
953  }
954  }
955 }
956 
957 void
958 qof_sql_query_parse (QofSqlQuery * query, const char *str)
959 {
960  GList *tables;
961  char *buf;
962  sql_select_statement *sss;
963  sql_where *swear;
964 
965  if (!query)
966  return;
967  ENTER (" ");
968  /* Delete old query, if any */
969  if (query->qof_query)
970  {
971  qof_query_destroy (query->qof_query);
972  sql_destroy (query->parse_result);
973  query->qof_query = NULL;
974  }
975 
976  /* Parse the SQL string */
977  buf = g_strdup (str);
978  query->parse_result = sql_parse (buf);
979  g_free (buf);
980 
981  if (!query->parse_result)
982  {
983  LEAVE ("parse error");
984  return;
985  }
986 
987  if ((SQL_select != query->parse_result->type)
988  && (SQL_insert != query->parse_result->type))
989  {
990  LEAVE
991  ("currently, only SELECT or INSERT statements are supported, "
992  "got type=%s", sql_type_as_string (query->parse_result->type));
993  return;
994  }
995 
996  /* If the user wrote "SELECT * FROM tablename WHERE ..."
997  * then we have a single global tablename. But if the
998  * user wrote "SELECT * FROM tableA, tableB WHERE ..."
999  * then we don't have a single unique table-name.
1000  */
1001  tables = sql_statement_get_tables (query->parse_result);
1002  if (1 == g_list_length (tables))
1003  {
1004  query->single_global_tablename = tables->data;
1005  }
1006  /* if this is an insert, we're done with the parse. */
1007  if (SQL_insert == query->parse_result->type)
1008  {
1009  query->qof_query = qof_query_create ();
1010  qof_query_set_insert_table (query);
1011  LEAVE (" insert statement parsed OK");
1012  return;
1013  }
1014  sss = query->parse_result->statement;
1015  swear = sss->where;
1016  if (swear)
1017  {
1018  /* Walk over the where terms, turn them into QOF predicates */
1019  query->qof_query = handle_where (query, swear);
1020  if (NULL == query->qof_query)
1021  {
1022  LEAVE (" no query found");
1023  return;
1024  }
1025  }
1026  else
1027  {
1028  query->qof_query = qof_query_create ();
1029  }
1030  /* Provide support for different sort orders */
1031  handle_sort_order (query, sss->order);
1032 
1033  /* We also want to set the type of thing to search for.
1034  * SELECT * FROM table1, table2, ... is not supported.
1035  * Use sequential queries and build a partial book.
1036  */
1037  qof_query_search_for (query->qof_query,
1038  query->single_global_tablename);
1039  LEAVE (" success");
1040 }
1041 
1042 /* ========================================================== */
1043 
1044 GList *
1045 qof_sql_query_run (QofSqlQuery * query, const char *str)
1046 {
1047  GList *results;
1048 
1049  if (!query)
1050  return NULL;
1051 
1052  qof_sql_query_parse (query, str);
1053  if (NULL == query->qof_query)
1054  {
1055  PINFO (" Null query");
1056  return NULL;
1057  }
1058 
1059  qof_query_set_book (query->qof_query, query->book);
1060  /* Maybe log this sucker */
1061  if (qof_log_check (log_module, QOF_LOG_DETAIL))
1062  {
1063  qof_query_print (query->qof_query);
1064  }
1065  if (SQL_insert == query->parse_result->type)
1066  {
1067  results = NULL;
1068  results = g_list_append (results, qof_query_insert (query));
1069  return results;
1070  }
1071 
1072  results = qof_query_run (query->qof_query);
1073 
1074  return results;
1075 }
1076 
1077 GList *
1078 qof_sql_query_rerun (QofSqlQuery * query)
1079 {
1080  GList *results;
1081 
1082  if (!query)
1083  return NULL;
1084 
1085  if (NULL == query->qof_query)
1086  return NULL;
1087 
1088  qof_query_set_book (query->qof_query, query->book);
1089 
1090  /* Maybe log this sucker */
1091  if (qof_log_check (log_module, QOF_LOG_DETAIL))
1092  {
1093  qof_query_print (query->qof_query);
1094  }
1095 
1096  results = qof_query_run (query->qof_query);
1097 
1098  return results;
1099 }
1100 
1101 /* ========================== END OF FILE =================== */