QOF: qofsql.c Source File

QOF 0.7.5

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 *
64 qof_sql_query_new (void)
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
492 qd = qof_date_parse (str, QOF_DATE_FORMAT_UTC);
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 =================== */
KVP_TYPE_TIMESPEC
Definition: kvpframe.h:121
qof_util_whitespace_filter
const gchar * qof_util_whitespace_filter(const gchar *val)
Definition: qofutil.c:231
QOF_TYPE_DATE
#define QOF_TYPE_DATE
Definition: deprecated.h:336
QOF_DATE_FORMAT_UTC
#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
qof_error_register
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:91
qof_object_new_instance
gpointer qof_object_new_instance(QofIdTypeConst type_name, QofBook *book)
Definition: qofobject.c:42
qof_query_kvp_predicate_path
QofQueryPredData * qof_query_kvp_predicate_path(QofQueryCompare how, const gchar *path, const KvpValue *value)
QofIdType
const gchar * QofIdType
Definition: qofid.h:81
PINFO
#define PINFO(format, args...)
Definition: qoflog.h:199
qof_sql_query_parse
void qof_sql_query_parse(QofSqlQuery *query, const gchar *str)
QofInstance_s
Definition: qofinstance-p.h:35
qof_class_is_registered
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:132
Timespec
struct timespec64 Timespec
QofNumeric
struct _QofNumeric QofNumeric
A rational-number type.
Definition: qofnumeric.h:61
qof_date_free
void qof_date_free(QofDate *date)
Definition: qofdate.c:608
_QofParam
Definition: qofclass.h:195
QOF_UTC_DATE_FORMAT
#define QOF_UTC_DATE_FORMAT
UTC date format string.
Definition: qofdate.h:244
KvpValueType
KvpValueType
possible types in the union KvpValue
Definition: kvpframe.h:87
QofEntity_s
Definition: qofid.h:147
string_to_guid
gboolean string_to_guid(const gchar *string, GUID *guid)
KVP_TYPE_GUID
Unique identifier.
Definition: kvpframe.h:118
qof_query_print
void qof_query_print(QofQuery *query)
Definition: qofquery.c:1577
KvpFrame
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
qof_sql_query_set_book
void qof_sql_query_set_book(QofSqlQuery *q, QofBook *book)
Definition: qofsql.c:102
timespec64
Definition: qoftime.h:97
qof_log_check
gboolean qof_log_check(QofLogModule log_module, QofLogLevel log_level)
Definition: qoflog.c:204
KVP_TYPE_GLIST
Definition: kvpframe.h:132
KVP_TYPE_FRAME
Definition: kvpframe.h:134
qof_util_bool_to_int
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:249
query_time_def
Definition: qofquerycore-p.h:83
qof_query_set_sort_increasing
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
Definition: qofquery.c:1282
QOF_GUID_MATCH_ANY
Definition: qofquerycore.h:108
qof_instance_get_book
QofBook * qof_instance_get_book(QofInstance *inst)
Definition: qofinstance.c:87
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
QofQuery
struct _QofQuery QofQuery
Definition: qofquery.h:85
qof_date_to_qtime
QofTime * qof_date_to_qtime(const QofDate *qd)
Definition: qofdate.c:892
QofDate_s
Full range replacement for struct tm.
Definition: qofdate.h:138
KVP_TYPE_NUMERIC
128bit denominator/numerator maths.
Definition: kvpframe.h:106
kvp_value_get_gint64
gint64 kvp_value_get_gint64(const KvpValue *value)
Definition: kvpframe.c:1402
qof_class_get_parameter
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const gchar *parameter)
Definition: qofclass.c:146
qof_date_parse
QofDate * qof_date_parse(const gchar *str, QofDateFormat df)
Convert a timestamp to a QofTime.
Definition: qofdate.c:525
KvpValue
struct _KvpValue KvpValue
Definition: kvpframe.h:78
qof_query_destroy
void qof_query_destroy(QofQuery *q)
Definition: qofquery.c:998
QofGuidMatch
QofGuidMatch
Definition: qofquerycore.h:104
timespecFromTime_t
void timespecFromTime_t(Timespec *ts, time_t t)
Definition: deprecated.c:304
qof_numeric_from_string
gboolean qof_numeric_from_string(const gchar *str, QofNumeric *n)
Definition: qofnumeric.c:1121
qof_sql_query_get_query
QofQuery * qof_sql_query_get_query(QofSqlQuery *q)
Definition: qofsql.c:92
qof_query_add_term
void qof_query_add_term(QofQuery *q, GSList *param_list, QofQueryPredData *pred_data, QofQueryOp op)
Definition: qofquery.c:691
KVP_TYPE_GINT64
64bit integer
Definition: kvpframe.h:94
qof_sql_query_set_kvp
void qof_sql_query_set_kvp(QofSqlQuery *q, KvpFrame *kvp)
Definition: qofsql.c:112
_QofNumeric
Definition: qofnumeric.h:52
qof_query_set_book
void qof_query_set_book(QofQuery *q, QofBook *book)
Definition: qofquery.c:1335
qof_query_set_sort_order
void qof_query_set_sort_order(QofQuery *q, GSList *params1, GSList *params2, GSList *params3)
Definition: qofquery.c:1247
qof_query_merge
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
Definition: qofquery.c:1127
QofQueryCompare
QofQueryCompare
Definition: qofquerycore.h:51
kvp_value_get_string
gchar * kvp_value_get_string(const KvpValue *value)
Definition: kvpframe.c:1447
QofCharMatch
QofCharMatch
Definition: qofquerycore.h:127
QofInstance_s::entity
QofEntity entity
Definition: qofinstance-p.h:38
qof_sql_query_new
QofSqlQuery * qof_sql_query_new(void)
Definition: qofsql.c:64
QofType
const gchar * QofType
Definition: qofclass.h:150
qof_query_invert
QofQuery * qof_query_invert(QofQuery *q)
Definition: qofquery.c:1043
qof_scan_date_secs
gboolean qof_scan_date_secs(const char *buff, time_t *secs)
_GUID
Definition: guid.h:53
QofQueryOp
QofQueryOp
Definition: qofquery.h:88
qof_query_run
GList * qof_query_run(QofQuery *q)
Definition: qofquery.c:757
QofIdTypeConst
const gchar * QofIdTypeConst
Definition: qofid.h:83
_QofQueryPredData
Definition: qofquerycore.h:138
PWARN
#define PWARN(format, args...)
Definition: qoflog.h:191
QofTime
struct QofTime64 QofTime
Use a 64-bit signed int QofTime.
Definition: qoftime.h:120
KVP_TYPE_BOOLEAN
Simple boolean type.
Definition: kvpframe.h:140
KVP_TYPE_BINARY
Definition: kvpframe.h:130
qof_class_get_parameter_type
QofType qof_class_get_parameter_type(QofIdTypeConst obj_name, const gchar *param_name)
Definition: qofclass.c:198
qof_book_get_backend
QofBackend * qof_book_get_backend(QofBook *book)
Retrieve the backend used by this book.
Definition: qofbook.c:154
qof_date_format_set
void qof_date_format_set(QofDateFormat df)
Definition: deprecated.c:1427
KVP_TYPE_STRING
standard C string
Definition: kvpframe.h:112
qof_query_date_predicate
QofQueryPredData * qof_query_date_predicate(QofQueryCompare how, QofDateMatch options, Timespec date)
Definition: qofquerycore.c:1848
_QofBook
Definition: qofbook-p.h:48
safe_strcmp
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:72
KVP_TYPE_DOUBLE
standard C double type
Definition: kvpframe.h:100
qof_sql_query_run
GList * qof_sql_query_run(QofSqlQuery *query, const gchar *str)
Perform the query, return the results.
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217
qof_query_create
QofQuery * qof_query_create(void)
Definition: qofquery.c:900
QofBackend_s
Definition: qofbackend-p.h:283
QofLogModule
const gchar * QofLogModule
Definition: qofid.h:85
QOF_QUERY_FIRST_TERM
#define QOF_QUERY_FIRST_TERM
Definition: qofquery.h:98
KVP_TYPE_TIME
64bit time/date handling.
Definition: kvpframe.h:128
qof_query_search_for
void qof_query_search_for(QofQuery *q, QofIdTypeConst obj_type)
Definition: qofquery.c:909
qof_sql_query_rerun
GList * qof_sql_query_rerun(QofSqlQuery *query)
Definition: qofsql.c:1078