00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #include <sys/types.h>
00027 #include <time.h>
00028 #include <glib.h>
00029 #include <regex.h>
00030 #include <string.h>
00031
00032 #include "gnc-trace.h"
00033 #include "gnc-engine-util.h"
00034
00035 #include "qofbackend-p.h"
00036 #include "qofbook.h"
00037 #include "qofbook-p.h"
00038 #include "qofclass.h"
00039 #include "qofclass-p.h"
00040 #include "qofobject.h"
00041 #include "qofquery.h"
00042 #include "qofquery-p.h"
00043 #include "qofquerycore.h"
00044 #include "qofquerycore-p.h"
00045
00046 static QofLogModule log_module = QOF_MOD_QUERY;
00047
00048 struct _QofQueryTerm
00049 {
00050 GSList * param_list;
00051 QofQueryPredData *pdata;
00052 gboolean invert;
00053
00054
00055
00056
00057
00058
00059 GSList * param_fcns;
00060 QofQueryPredicateFunc pred_fcn;
00061 };
00062
00063 struct _QofQuerySort
00064 {
00065 GSList * param_list;
00066 gint options;
00067 gboolean increasing;
00068
00069
00070
00071
00072
00073
00074 gboolean use_default;
00075 GSList * param_fcns;
00076 QofSortFunc obj_cmp;
00077 QofCompareFunc comp_fcn;
00078 };
00079
00080
00081 struct _QofQuery
00082 {
00083
00084 QofIdType search_for;
00085
00086
00087
00088 GList * terms;
00089
00090
00091
00092 QofQuerySort primary_sort;
00093 QofQuerySort secondary_sort;
00094 QofQuerySort tertiary_sort;
00095 QofSortFunc defaultSort;
00096
00097
00098 int max_results;
00099
00100
00101 GList * books;
00102
00103
00104 GHashTable* be_compiled;
00105
00106
00107
00108 int changed;
00109
00110 GList * results;
00111 };
00112
00113 typedef struct _QofQueryCB
00114 {
00115 QofQuery * query;
00116 GList * list;
00117 int count;
00118 } QofQueryCB;
00119
00120
00121 static void query_init (QofQuery *q, QofQueryTerm *initial_term)
00122 {
00123 GList * or = NULL;
00124 GList *and = NULL;
00125 GHashTable *ht;
00126
00127 if (initial_term) {
00128 or = g_list_alloc ();
00129 and = g_list_alloc ();
00130 and->data = initial_term;
00131 or->data = and;
00132 }
00133
00134 if(q->terms)
00135 qof_query_clear (q);
00136
00137 g_list_free (q->results);
00138 g_list_free (q->books);
00139
00140 g_slist_free (q->primary_sort.param_list);
00141 g_slist_free (q->secondary_sort.param_list);
00142 g_slist_free (q->tertiary_sort.param_list);
00143
00144 g_slist_free (q->primary_sort.param_fcns);
00145 g_slist_free (q->secondary_sort.param_fcns);
00146 g_slist_free (q->tertiary_sort.param_fcns);
00147
00148 ht = q->be_compiled;
00149 memset (q, 0, sizeof (*q));
00150 q->be_compiled = ht;
00151
00152 q->terms = or;
00153 q->changed = 1;
00154 q->max_results = -1;
00155
00156 q->primary_sort.param_list = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
00157 q->primary_sort.increasing = TRUE;
00158 q->secondary_sort.increasing = TRUE;
00159 q->tertiary_sort.increasing = TRUE;
00160 }
00161
00162 static void swap_terms (QofQuery *q1, QofQuery *q2)
00163 {
00164 GList *g;
00165
00166 if (!q1 || !q2) return;
00167
00168 g = q1->terms;
00169 q1->terms = q2->terms;
00170 q2->terms = g;
00171
00172 g = q1->books;
00173 q1->books = q2->books;
00174 q2->books = g;
00175
00176 q1->changed = 1;
00177 q2->changed = 1;
00178 }
00179
00180 static void free_query_term (QofQueryTerm *qt)
00181 {
00182 if (!qt) return;
00183
00184 qof_query_core_predicate_free (qt->pdata);
00185 g_slist_free (qt->param_list);
00186 g_slist_free (qt->param_fcns);
00187 g_free (qt);
00188 }
00189
00190 static QofQueryTerm * copy_query_term (QofQueryTerm *qt)
00191 {
00192 QofQueryTerm *new_qt;
00193 if (!qt) return NULL;
00194
00195 new_qt = g_new0 (QofQueryTerm, 1);
00196 memcpy (new_qt, qt, sizeof(QofQueryTerm));
00197 new_qt->param_list = g_slist_copy (qt->param_list);
00198 new_qt->param_fcns = g_slist_copy (qt->param_fcns);
00199 new_qt->pdata = qof_query_core_predicate_copy (qt->pdata);
00200 return new_qt;
00201 }
00202
00203 static GList * copy_and_terms (GList *and_terms)
00204 {
00205 GList *and = NULL;
00206 GList *cur_and;
00207
00208 for(cur_and = and_terms; cur_and; cur_and = cur_and->next)
00209 {
00210 and = g_list_prepend(and, copy_query_term (cur_and->data));
00211 }
00212
00213 return g_list_reverse(and);
00214 }
00215
00216 static GList *
00217 copy_or_terms(GList * or_terms)
00218 {
00219 GList * or = NULL;
00220 GList * cur_or;
00221
00222 for(cur_or = or_terms; cur_or; cur_or = cur_or->next)
00223 {
00224 or = g_list_prepend(or, copy_and_terms(cur_or->data));
00225 }
00226
00227 return g_list_reverse(or);
00228 }
00229
00230 static void copy_sort (QofQuerySort *dst, const QofQuerySort *src)
00231 {
00232 memcpy (dst, src, sizeof (*dst));
00233 dst->param_list = g_slist_copy (src->param_list);
00234 dst->param_fcns = g_slist_copy (src->param_fcns);
00235 }
00236
00237 static void free_sort (QofQuerySort *s)
00238 {
00239 g_slist_free (s->param_list);
00240 s->param_list = NULL;
00241
00242 g_slist_free (s->param_fcns);
00243 s->param_fcns = NULL;
00244 }
00245
00246 static void free_members (QofQuery *q)
00247 {
00248 GList * cur_or;
00249
00250 if (q == NULL) return;
00251
00252 for(cur_or = q->terms; cur_or; cur_or = cur_or->next)
00253 {
00254 GList * cur_and;
00255
00256 for(cur_and = cur_or->data; cur_and; cur_and = cur_and->next)
00257 {
00258 free_query_term(cur_and->data);
00259 cur_and->data = NULL;
00260 }
00261
00262 g_list_free(cur_or->data);
00263 cur_or->data = NULL;
00264 }
00265
00266 free_sort (&(q->primary_sort));
00267 free_sort (&(q->secondary_sort));
00268 free_sort (&(q->tertiary_sort));
00269
00270 g_list_free(q->terms);
00271 q->terms = NULL;
00272
00273 g_list_free(q->books);
00274 q->books = NULL;
00275
00276 g_list_free(q->results);
00277 q->results = NULL;
00278 }
00279
00280 static int cmp_func (QofQuerySort *sort, QofSortFunc default_sort,
00281 gconstpointer a, gconstpointer b)
00282 {
00283 QofParam *param = NULL;
00284 GSList *node;
00285 gpointer conva, convb;
00286
00287 g_return_val_if_fail (sort, 0);
00288
00289
00290 if (sort->use_default)
00291 {
00292 if (default_sort) return default_sort ((gpointer)a, (gpointer)b);
00293 return 0;
00294 }
00295
00296
00297 if (!sort->param_fcns) return 0;
00298
00299
00300 if (!sort->comp_fcn && !sort->obj_cmp) return 0;
00301
00302
00303 conva = (gpointer)a;
00304 convb = (gpointer)b;
00305 for (node = sort->param_fcns; node; node = node->next)
00306 {
00307 param = node->data;
00308
00309
00310
00311 if (!node->next && !sort->obj_cmp)
00312 break;
00313
00314
00315 conva = (param->param_getfcn) (conva, param);
00316 convb = (param->param_getfcn) (convb, param);
00317 }
00318
00319
00320 if (sort->comp_fcn)
00321 {
00322 int rc = sort->comp_fcn (conva, convb, sort->options, param);
00323 return rc;
00324 }
00325
00326 return sort->obj_cmp (conva, convb);
00327 }
00328
00329 static QofQuery * sortQuery = NULL;
00330
00331 static int sort_func (gconstpointer a, gconstpointer b)
00332 {
00333 int retval;
00334
00335 g_return_val_if_fail (sortQuery, 0);
00336
00337 retval = cmp_func (&(sortQuery->primary_sort), sortQuery->defaultSort, a, b);
00338 if (retval == 0)
00339 {
00340 retval = cmp_func (&(sortQuery->secondary_sort), sortQuery->defaultSort,
00341 a, b);
00342 if (retval == 0)
00343 {
00344 retval = cmp_func (&(sortQuery->tertiary_sort), sortQuery->defaultSort,
00345 a, b);
00346 return sortQuery->tertiary_sort.increasing ? retval : -retval;
00347 }
00348 else
00349 {
00350 return sortQuery->secondary_sort.increasing ? retval : -retval;
00351 }
00352 }
00353 else
00354 {
00355 return sortQuery->primary_sort.increasing ? retval : -retval;
00356 }
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 static int
00366 check_object (QofQuery *q, gpointer object)
00367 {
00368 GList * and_ptr;
00369 GList * or_ptr;
00370 QofQueryTerm * qt;
00371 int and_terms_ok=1;
00372
00373 ENTER (" object=%p terms=%p name=%s",
00374 object, q->terms, qof_object_printable (q->search_for, object));
00375
00376 for(or_ptr = q->terms; or_ptr; or_ptr = or_ptr->next)
00377 {
00378 and_terms_ok = 1;
00379 for(and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next)
00380 {
00381 qt = (QofQueryTerm *)(and_ptr->data);
00382 if (qt->param_fcns && qt->pred_fcn)
00383 {
00384 GSList *node;
00385 QofParam *param = NULL;
00386 gpointer conv_obj = object;
00387
00388
00389 for (node = qt->param_fcns; node; node = node->next)
00390 {
00391 param = node->data;
00392
00393
00394 if (!node->next) break;
00395
00396 conv_obj = param->param_getfcn (conv_obj, param);
00397 }
00398
00399 if (((qt->pred_fcn)(conv_obj, param, qt->pdata)) == qt->invert)
00400 {
00401 and_terms_ok = 0;
00402 break;
00403 }
00404 }
00405 else
00406 {
00407
00408 }
00409 }
00410 if (and_terms_ok)
00411 {
00412 LEAVE (" (terms are OK)");
00413 return 1;
00414 }
00415 }
00416
00417
00418
00419
00420
00421
00422 LEAVE (" ");
00423 if (NULL == q->terms) return 1;
00424 return 0;
00425 }
00426
00427
00428
00429
00430
00431
00432
00433 static GSList *
00434 compile_params (GSList *param_list, QofIdType start_obj,
00435 QofParam const **final)
00436 {
00437 const QofParam *objDef = NULL;
00438 GSList *fcns = NULL;
00439
00440 ENTER ("param_list=%p id=%s", param_list, start_obj);
00441 g_return_val_if_fail (param_list, NULL);
00442 g_return_val_if_fail (start_obj, NULL);
00443 g_return_val_if_fail (final, NULL);
00444
00445 for (; param_list; param_list = param_list->next)
00446 {
00447 QofIdType param_name = param_list->data;
00448 objDef = qof_class_get_parameter (start_obj, param_name);
00449
00450
00451 if (!objDef) break;
00452
00453
00454 fcns = g_slist_prepend (fcns, (gpointer) objDef);
00455
00456
00457 *final = objDef;
00458
00459
00460 start_obj = (QofIdType) objDef->param_type;
00461 }
00462
00463 LEAVE ("fcns=%p", fcns);
00464 return (g_slist_reverse (fcns));
00465 }
00466
00467 static void
00468 compile_sort (QofQuerySort *sort, QofIdType obj)
00469 {
00470 const QofParam *resObj = NULL;
00471
00472 ENTER ("sort=%p id=%s params=%p", sort, obj, sort->param_list);
00473 sort->use_default = FALSE;
00474
00475 g_slist_free (sort->param_fcns);
00476 sort->param_fcns = NULL;
00477 sort->comp_fcn = NULL;
00478 sort->obj_cmp = NULL;
00479
00480
00481 if (!sort->param_list) { LEAVE (" "); return; }
00482
00483
00484 sort->param_fcns = compile_params (sort->param_list, obj, &resObj);
00485
00486
00487
00488
00489 if (sort->param_fcns)
00490 {
00491 sort->comp_fcn = qof_query_core_get_compare (resObj->param_type);
00492
00493
00494 if (sort->comp_fcn == NULL)
00495 {
00496 sort->obj_cmp = qof_class_get_default_sort (resObj->param_type);
00497 }
00498 }
00499 else if (!safe_strcmp (sort->param_list->data, QUERY_DEFAULT_SORT))
00500 {
00501 sort->use_default = TRUE;
00502 }
00503 LEAVE ("sort=%p id=%s", sort, obj);
00504 }
00505
00506 static void compile_terms (QofQuery *q)
00507 {
00508 GList *or_ptr, *and_ptr, *node;
00509
00510 ENTER (" query=%p", q);
00511
00512
00513
00514 for (or_ptr = q->terms; or_ptr; or_ptr = or_ptr->next) {
00515 for (and_ptr = or_ptr->data; and_ptr; and_ptr = and_ptr->next) {
00516 QofQueryTerm *qt = and_ptr->data;
00517 const QofParam *resObj = NULL;
00518
00519 g_slist_free (qt->param_fcns);
00520 qt->param_fcns = NULL;
00521
00522
00523 qt->param_fcns = compile_params (qt->param_list, q->search_for,
00524 &resObj);
00525
00526
00527
00528
00529
00530 if (qt->param_fcns)
00531 qt->pred_fcn = qof_query_core_get_predicate (resObj->param_type);
00532 else
00533 qt->pred_fcn = NULL;
00534 }
00535 }
00536
00537
00538 compile_sort (&(q->primary_sort), q->search_for);
00539 compile_sort (&(q->secondary_sort), q->search_for);
00540 compile_sort (&(q->tertiary_sort), q->search_for);
00541
00542 q->defaultSort = qof_class_get_default_sort (q->search_for);
00543
00544
00545 for (node = q->books; node; node = node->next) {
00546 QofBook *book = node->data;
00547 QofBackend *be = book->backend;
00548
00549 if (be && be->compile_query) {
00550 gpointer result = (be->compile_query)(be, q);
00551 if (result)
00552 g_hash_table_insert (q->be_compiled, book, result);
00553 }
00554 }
00555 LEAVE (" query=%p", q);
00556 }
00557
00558 static void check_item_cb (gpointer object, gpointer user_data)
00559 {
00560 QofQueryCB *ql = user_data;
00561
00562 if (!object || !ql) return;
00563
00564 if (check_object (ql->query, object)) {
00565 ql->list = g_list_prepend (ql->list, object);
00566 ql->count++;
00567 }
00568 return;
00569 }
00570
00571 static int param_list_cmp (GSList *l1, GSList *l2)
00572 {
00573 while (1) {
00574 int ret;
00575
00576
00577 if (!l1 && !l2) return 0;
00578 if (!l1 && l2) return -1;
00579 if (l1 && !l2) return 1;
00580
00581 ret = safe_strcmp (l1->data, l2->data);
00582 if (ret)
00583 return ret;
00584
00585 l1 = l1->next;
00586 l2 = l2->next;
00587 }
00588 }
00589
00590 static GList * merge_books (GList *l1, GList *l2)
00591 {
00592 GList *res = NULL;
00593 GList *node;
00594
00595 res = g_list_copy (l1);
00596
00597 for (node = l2; node; node = node->next) {
00598 if (g_list_index (res, node->data) == -1)
00599 res = g_list_prepend (res, node->data);
00600 }
00601
00602 return res;
00603 }
00604
00605 static gboolean
00606 query_free_compiled (gpointer key, gpointer value, gpointer not_used)
00607 {
00608 QofBook* book = key;
00609 QofBackend* be = book->backend;
00610
00611 if (be && be->free_query)
00612 (be->free_query)(be, value);
00613
00614 return TRUE;
00615 }
00616
00617
00618 static void query_clear_compiles (QofQuery *q)
00619 {
00620 g_hash_table_foreach_remove (q->be_compiled, query_free_compiled, NULL);
00621 }
00622
00623
00624
00625
00626 GSList *
00627 qof_query_build_param_list (char const *param, ...)
00628 {
00629 GSList *param_list = NULL;
00630 char const *this_param;
00631 va_list ap;
00632
00633 if (!param)
00634 return NULL;
00635
00636 va_start (ap, param);
00637
00638 for (this_param = param; this_param; this_param = va_arg (ap, const char *))
00639 param_list = g_slist_prepend (param_list, (gpointer)this_param);
00640
00641 va_end (ap);
00642
00643 return g_slist_reverse (param_list);
00644 }
00645
00646 void qof_query_add_term (QofQuery *q, GSList *param_list,
00647 QofQueryPredData *pred_data, QofQueryOp op)
00648 {
00649 QofQueryTerm *qt;
00650 QofQuery *qr, *qs;
00651
00652 if (!q || !param_list || !pred_data) return;
00653
00654 qt = g_new0 (QofQueryTerm, 1);
00655 qt->param_list = param_list;
00656 qt->pdata = pred_data;
00657 qs = qof_query_create ();
00658 query_init (qs, qt);
00659
00660 if (qof_query_has_terms (q))
00661 qr = qof_query_merge (q, qs, op);
00662 else
00663 qr = qof_query_merge (q, qs, QOF_QUERY_OR);
00664
00665 swap_terms (q, qr);
00666 qof_query_destroy (qs);
00667 qof_query_destroy (qr);
00668 }
00669
00670 void qof_query_purge_terms (QofQuery *q, GSList *param_list)
00671 {
00672 QofQueryTerm *qt;
00673 GList *or, *and;
00674
00675 if (!q || !param_list) return;
00676
00677 for (or = q->terms; or; or = or->next) {
00678 for (and = or->data; and; and = and->next) {
00679 qt = and->data;
00680 if (!param_list_cmp (qt->param_list, param_list)) {
00681 if (g_list_length (or->data) == 1) {
00682 q->terms = g_list_remove_link (q->terms, or);
00683 g_list_free_1 (or);
00684 or = q->terms;
00685 break;
00686 } else {
00687 or->data = g_list_remove_link (or->data, and);
00688 g_list_free_1 (and);
00689 and = or->data;
00690 if (!and) break;
00691 }
00692 q->changed = 1;
00693 free_query_term (qt);
00694 }
00695 }
00696 if (!or) break;
00697 }
00698 }
00699
00700 GList * qof_query_run (QofQuery *q)
00701 {
00702 GList *matching_objects = NULL;
00703 GList *node;
00704 int object_count = 0;
00705
00706 if (!q) return NULL;
00707 g_return_val_if_fail (q->search_for, NULL);
00708 g_return_val_if_fail (q->books, NULL);
00709 ENTER (" q=%p", q);
00710
00711
00712
00713
00714 if (q->changed)
00715 {
00716 query_clear_compiles (q);
00717 compile_terms (q);
00718 }
00719
00720
00721 if (gnc_should_log (log_module, GNC_LOG_DETAIL)) qof_query_print (q);
00722
00723
00724 {
00725 QofQueryCB qcb;
00726
00727 memset (&qcb, 0, sizeof (qcb));
00728 qcb.query = q;
00729
00730
00731 for (node=q->books; node; node=node->next)
00732 {
00733 QofBook *book = node->data;
00734 QofBackend *be = book->backend;
00735
00736
00737 if (be)
00738 {
00739 gpointer compiled_query = g_hash_table_lookup (q->be_compiled, book);
00740
00741 if (compiled_query && be->run_query)
00742 {
00743 (be->run_query) (be, compiled_query);
00744 }
00745 }
00746
00747
00748 qof_object_foreach (q->search_for, book, (QofEntityForeachCB) check_item_cb, &qcb);
00749 }
00750
00751 matching_objects = qcb.list;
00752 object_count = qcb.count;
00753 }
00754 PINFO ("matching objects=%p count=%d", matching_objects, object_count);
00755
00756
00757
00758
00759
00760
00761
00762 matching_objects = g_list_reverse(matching_objects);
00763
00764
00765
00766
00767
00768 if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp ||
00769 (q->primary_sort.use_default && q->defaultSort))
00770 {
00771 sortQuery = q;
00772 matching_objects = g_list_sort(matching_objects, sort_func);
00773 sortQuery = NULL;
00774 }
00775
00776
00777 if((object_count > q->max_results) && (q->max_results > -1))
00778 {
00779 if(q->max_results > 0)
00780 {
00781 GList *mptr;
00782
00783
00784 mptr = g_list_nth(matching_objects, object_count - q->max_results);
00785
00786 if (mptr != NULL)
00787 {
00788 if (mptr->prev != NULL) mptr->prev->next = NULL;
00789 mptr->prev = NULL;
00790 }
00791 g_list_free(matching_objects);
00792 matching_objects = mptr;
00793 }
00794 else
00795 {
00796
00797 g_list_free(matching_objects);
00798 matching_objects = NULL;
00799 }
00800 object_count = q->max_results;
00801 }
00802
00803 q->changed = 0;
00804
00805 g_list_free(q->results);
00806 q->results = matching_objects;
00807
00808 LEAVE (" q=%p", q);
00809 return matching_objects;
00810 }
00811
00812 GList *
00813 qof_query_last_run (QofQuery *query)
00814 {
00815 if (!query)
00816 return NULL;
00817
00818 return query->results;
00819 }
00820
00821 void qof_query_clear (QofQuery *query)
00822 {
00823 QofQuery *q2 = qof_query_create ();
00824 swap_terms (query, q2);
00825 qof_query_destroy (q2);
00826
00827 g_list_free (query->books);
00828 query->books = NULL;
00829 g_list_free (query->results);
00830 query->results = NULL;
00831 query->changed = 1;
00832 }
00833
00834 QofQuery * qof_query_create (void)
00835 {
00836 QofQuery *qp = g_new0 (QofQuery, 1);
00837 qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal);
00838 query_init (qp, NULL);
00839 return qp;
00840 }
00841
00842 void qof_query_search_for (QofQuery *q, QofIdTypeConst obj_type)
00843 {
00844 if (!q || !obj_type)
00845 return;
00846
00847 if (safe_strcmp (q->search_for, obj_type)) {
00848 q->search_for = (QofIdType) obj_type;
00849 q->changed = 1;
00850 }
00851 }
00852
00853 QofQuery * qof_query_create_for (QofIdTypeConst obj_type)
00854 {
00855 QofQuery *q;
00856 if (!obj_type)
00857 return NULL;
00858 q = qof_query_create ();
00859 qof_query_search_for (q, obj_type);
00860 return q;
00861 }
00862
00863 int qof_query_has_terms (QofQuery *q)
00864 {
00865 if (!q) return 0;
00866 return g_list_length (q->terms);
00867 }
00868
00869 int qof_query_num_terms (QofQuery *q)
00870 {
00871 GList *o;
00872 int n = 0;
00873 if (!q) return 0;
00874 for (o = q->terms; o; o=o->next)
00875 n += g_list_length(o->data);
00876 return n;
00877 }
00878
00879 gboolean qof_query_has_term_type (QofQuery *q, GSList *term_param)
00880 {
00881 GList *or;
00882 GList *and;
00883
00884 if (!q || !term_param)
00885 return FALSE;
00886
00887 for(or = q->terms; or; or = or->next) {
00888 for(and = or->data; and; and = and->next) {
00889 QofQueryTerm *qt = and->data;
00890 if (!param_list_cmp (term_param, qt->param_list))
00891 return TRUE;
00892 }
00893 }
00894
00895 return FALSE;
00896 }
00897
00898 GSList * qof_query_get_term_type (QofQuery *q, GSList *term_param)
00899 {
00900 GList *or;
00901 GList *and;
00902 GSList *results = NULL;
00903
00904 if (!q || !term_param)
00905 return FALSE;
00906
00907 for(or = q->terms; or; or = or->next) {
00908 for(and = or->data; and; and = and->next) {
00909 QofQueryTerm *qt = and->data;
00910 if (!param_list_cmp (term_param, qt->param_list))
00911 results = g_slist_append(results, qt->pdata);
00912 }
00913 }
00914
00915 return results;
00916 }
00917
00918 void qof_query_destroy (QofQuery *q)
00919 {
00920 if (!q) return;
00921 free_members (q);
00922 query_clear_compiles (q);
00923 g_hash_table_destroy (q->be_compiled);
00924 g_free (q);
00925 }
00926
00927 QofQuery * qof_query_copy (QofQuery *q)
00928 {
00929 QofQuery *copy;
00930 GHashTable *ht;
00931
00932 if (!q) return NULL;
00933 copy = qof_query_create ();
00934 ht = copy->be_compiled;
00935 free_members (copy);
00936
00937 memcpy (copy, q, sizeof (QofQuery));
00938
00939 copy->be_compiled = ht;
00940 copy->terms = copy_or_terms (q->terms);
00941 copy->books = g_list_copy (q->books);
00942 copy->results = g_list_copy (q->results);
00943
00944 copy_sort (&(copy->primary_sort), &(q->primary_sort));
00945 copy_sort (&(copy->secondary_sort), &(q->secondary_sort));
00946 copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort));
00947
00948 copy->changed = 1;
00949
00950 return copy;
00951 }
00952
00953
00954
00955
00956
00957
00958
00959 QofQuery * qof_query_invert (QofQuery *q)
00960 {
00961 QofQuery * retval;
00962 QofQuery * right, * left, * iright, * ileft;
00963 QofQueryTerm * qt;
00964 GList * aterms;
00965 GList * cur;
00966 GList * new_oterm;
00967 int num_or_terms;
00968
00969 if (!q)
00970 return NULL;
00971
00972 num_or_terms = g_list_length(q->terms);
00973
00974 switch(num_or_terms)
00975 {
00976 case 0:
00977 retval = qof_query_create();
00978 retval->max_results = q->max_results;
00979 break;
00980
00981
00982
00983 case 1:
00984 retval = qof_query_create();
00985 retval->max_results = q->max_results;
00986 retval->books = g_list_copy (q->books);
00987 retval->search_for = q->search_for;
00988 retval->changed = 1;
00989
00990 aterms = g_list_nth_data(q->terms, 0);
00991 new_oterm = NULL;
00992 for(cur=aterms; cur; cur=cur->next) {
00993 qt = copy_query_term(cur->data);
00994 qt->invert = !(qt->invert);
00995 new_oterm = g_list_append(NULL, qt);
00996
00997
00998
00999
01000 retval->terms = g_list_reverse(retval->terms);
01001 retval->terms = g_list_prepend(retval->terms, new_oterm);
01002 retval->terms = g_list_reverse(retval->terms);
01003 }
01004 break;
01005
01006
01007
01008
01009 default:
01010 right = qof_query_create();
01011 right->terms = copy_or_terms(g_list_nth(q->terms, 1));
01012
01013 left = qof_query_create();
01014 left->terms = g_list_append(NULL,
01015 copy_and_terms(g_list_nth_data(q->terms, 0)));
01016
01017 iright = qof_query_invert(right);
01018 ileft = qof_query_invert(left);
01019
01020 retval = qof_query_merge(iright, ileft, QOF_QUERY_AND);
01021 retval->books = g_list_copy (q->books);
01022 retval->max_results = q->max_results;
01023 retval->search_for = q->search_for;
01024 retval->changed = 1;
01025
01026 qof_query_destroy(iright);
01027 qof_query_destroy(ileft);
01028 qof_query_destroy(right);
01029 qof_query_destroy(left);
01030 break;
01031 }
01032
01033 return retval;
01034 }
01035
01036
01037
01038
01039
01040
01041 QofQuery *
01042 qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
01043 {
01044
01045 QofQuery * retval = NULL;
01046 QofQuery * i1, * i2;
01047 QofQuery * t1, * t2;
01048 GList * i, * j;
01049 QofIdType search_for;
01050
01051 if(!q1) return q2;
01052 if(!q2) return q1;
01053
01054 if (q1->search_for && q2->search_for)
01055 g_return_val_if_fail (safe_strcmp (q1->search_for, q2->search_for) == 0,
01056 NULL);
01057
01058 search_for = (q1->search_for ? q1->search_for : q2->search_for);
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069 if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1)))
01070 {
01071 op = QOF_QUERY_OR;
01072 }
01073
01074 switch(op)
01075 {
01076 case QOF_QUERY_OR:
01077 retval = qof_query_create();
01078 retval->terms =
01079 g_list_concat(copy_or_terms(q1->terms), copy_or_terms(q2->terms));
01080 retval->books = merge_books (q1->books, q2->books);
01081 retval->max_results = q1->max_results;
01082 retval->changed = 1;
01083 break;
01084
01085 case QOF_QUERY_AND:
01086 retval = qof_query_create();
01087 retval->books = merge_books (q1->books, q2->books);
01088 retval->max_results = q1->max_results;
01089 retval->changed = 1;
01090
01091
01092
01093
01094
01095 for(i=q1->terms; i; i=i->next)
01096 {
01097 for(j=q2->terms; j; j=j->next)
01098 {
01099 retval->terms =
01100 g_list_prepend(retval->terms,
01101 g_list_concat
01102 (copy_and_terms(i->data),
01103 copy_and_terms(j->data)));
01104 }
01105 }
01106 retval->terms = g_list_reverse(retval->terms);
01107 break;
01108
01109 case QOF_QUERY_NAND:
01110
01111 i1 = qof_query_invert(q1);
01112 i2 = qof_query_invert(q2);
01113 retval = qof_query_merge(i1, i2, QOF_QUERY_OR);
01114 qof_query_destroy(i1);
01115 qof_query_destroy(i2);
01116 break;
01117
01118 case QOF_QUERY_NOR:
01119
01120 i1 = qof_query_invert(q1);
01121 i2 = qof_query_invert(q2);
01122 retval = qof_query_merge(i1, i2, QOF_QUERY_AND);
01123 qof_query_destroy(i1);
01124 qof_query_destroy(i2);
01125 break;
01126
01127 case QOF_QUERY_XOR:
01128
01129 i1 = qof_query_invert(q1);
01130 i2 = qof_query_invert(q2);
01131 t1 = qof_query_merge(q1, i2, QOF_QUERY_AND);
01132 t2 = qof_query_merge(i1, q2, QOF_QUERY_AND);
01133 retval = qof_query_merge(t1, t2, QOF_QUERY_OR);
01134
01135 qof_query_destroy(i1);
01136 qof_query_destroy(i2);
01137 qof_query_destroy(t1);
01138 qof_query_destroy(t2);
01139 break;
01140 }
01141
01142 retval->search_for = search_for;
01143 return retval;
01144 }
01145
01146 void
01147 qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op)
01148 {
01149 QofQuery *tmp_q;
01150
01151 if (!q1 || !q2)
01152 return;
01153
01154 tmp_q = qof_query_merge (q1, q2, op);
01155 swap_terms (q1, tmp_q);
01156 qof_query_destroy (tmp_q);
01157 }
01158
01159 void
01160 qof_query_set_sort_order (QofQuery *q,
01161 GSList *params1, GSList *params2, GSList *params3)
01162 {
01163 if (!q) return;
01164 if (q->primary_sort.param_list)
01165 g_slist_free (q->primary_sort.param_list);
01166 q->primary_sort.param_list = params1;
01167 q->primary_sort.options = 0;
01168
01169 if (q->secondary_sort.param_list)
01170 g_slist_free (q->secondary_sort.param_list);
01171 q->secondary_sort.param_list = params2;
01172 q->secondary_sort.options = 0;
01173
01174 if (q->tertiary_sort.param_list)
01175 g_slist_free (q->tertiary_sort.param_list);
01176 q->tertiary_sort.param_list = params3;
01177 q->tertiary_sort.options = 0;
01178
01179 q->changed = 1;
01180 }
01181
01182 void qof_query_set_sort_options (QofQuery *q, gint prim_op, gint sec_op,
01183 gint tert_op)
01184 {
01185 if (!q) return;
01186 q->primary_sort.options = prim_op;
01187 q->secondary_sort.options = sec_op;
01188 q->tertiary_sort.options = tert_op;
01189 }
01190
01191 void qof_query_set_sort_increasing (QofQuery *q, gboolean prim_inc,
01192 gboolean sec_inc, gboolean tert_inc)
01193 {
01194 if (!q) return;
01195 q->primary_sort.increasing = prim_inc;
01196 q->secondary_sort.increasing = sec_inc;
01197 q->tertiary_sort.increasing = tert_inc;
01198 }
01199
01200 void qof_query_set_max_results (QofQuery *q, int n)
01201 {
01202 if (!q) return;
01203 q->max_results = n;
01204 }
01205
01206 void qof_query_add_guid_list_match (QofQuery *q, GSList *param_list,
01207 GList *guid_list, QofGuidMatch options,
01208 QofQueryOp op)
01209 {
01210 QofQueryPredData *pdata;
01211
01212 if (!q || !param_list) return;
01213
01214 if (!guid_list)
01215 g_return_if_fail (options == QOF_GUID_MATCH_NULL);
01216
01217 pdata = qof_query_guid_predicate (options, guid_list);
01218 qof_query_add_term (q, param_list, pdata, op);
01219 }
01220
01221 void qof_query_add_guid_match (QofQuery *q, GSList *param_list,
01222 const GUID *guid, QofQueryOp op)
01223 {
01224 GList *g = NULL;
01225
01226 if (!q || !param_list) return;
01227
01228 if (guid)
01229 g = g_list_prepend (g, (gpointer)guid);
01230
01231 qof_query_add_guid_list_match (q, param_list, g,
01232 g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op);
01233
01234 g_list_free (g);
01235 }
01236
01237 void qof_query_set_book (QofQuery *q, QofBook *book)
01238 {
01239 GSList *slist = NULL;
01240 if (!q || !book) return;
01241
01242
01243 if (g_list_index (q->books, book) == -1)
01244 q->books = g_list_prepend (q->books, book);
01245
01246 g_slist_prepend (slist, QOF_PARAM_GUID);
01247 g_slist_prepend (slist, QOF_PARAM_BOOK);
01248 qof_query_add_guid_match (q, slist,
01249 qof_book_get_guid(book), QOF_QUERY_AND);
01250 }
01251
01252 GList * qof_query_get_books (QofQuery *q)
01253 {
01254 if (!q) return NULL;
01255 return q->books;
01256 }
01257
01258 void qof_query_add_boolean_match (QofQuery *q, GSList *param_list, gboolean value,
01259 QofQueryOp op)
01260 {
01261 QofQueryPredData *pdata;
01262 if (!q || !param_list) return;
01263
01264 pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value);
01265 qof_query_add_term (q, param_list, pdata, op);
01266 }
01267
01268
01269
01270
01271 void qof_query_init (void)
01272 {
01273 ENTER (" ");
01274 qof_query_core_init ();
01275 qof_class_init ();
01276 }
01277
01278 void qof_query_shutdown (void)
01279 {
01280 qof_class_shutdown ();
01281 qof_query_core_shutdown ();
01282 }
01283
01284 int qof_query_get_max_results (QofQuery *q)
01285 {
01286 if (!q) return 0;
01287 return q->max_results;
01288 }
01289
01290 QofIdType qof_query_get_search_for (QofQuery *q)
01291 {
01292 if (!q) return NULL;
01293 return q->search_for;
01294 }
01295
01296 GList * qof_query_get_terms (QofQuery *q)
01297 {
01298 if (!q) return NULL;
01299 return q->terms;
01300 }
01301
01302 GSList * qof_query_term_get_param_path (QofQueryTerm *qt)
01303 {
01304 if (!qt)
01305 return NULL;
01306 return qt->param_list;
01307 }
01308
01309 QofQueryPredData *qof_query_term_get_pred_data (QofQueryTerm *qt)
01310 {
01311 if (!qt)
01312 return NULL;
01313 return qt->pdata;
01314 }
01315
01316 gboolean qof_query_term_is_inverted (QofQueryTerm *qt)
01317 {
01318 if (!qt)
01319 return FALSE;
01320 return qt->invert;
01321 }
01322
01323 void qof_query_get_sorts (QofQuery *q, QofQuerySort **primary,
01324 QofQuerySort **secondary, QofQuerySort **tertiary)
01325 {
01326 if (!q)
01327 return;
01328 if (primary)
01329 *primary = &(q->primary_sort);
01330 if (secondary)
01331 *secondary = &(q->secondary_sort);
01332 if (tertiary)
01333 *tertiary = &(q->tertiary_sort);
01334 }
01335
01336 GSList * qof_query_sort_get_param_path (QofQuerySort *qs)
01337 {
01338 if (!qs)
01339 return NULL;
01340 return qs->param_list;
01341 }
01342
01343 gint qof_query_sort_get_sort_options (QofQuerySort *qs)
01344 {
01345 if (!qs)
01346 return 0;
01347 return qs->options;
01348 }
01349
01350 gboolean qof_query_sort_get_increasing (QofQuerySort *qs)
01351 {
01352 if (!qs)
01353 return FALSE;
01354 return qs->increasing;
01355 }
01356
01357 static gboolean
01358 qof_query_term_equal (QofQueryTerm *qt1, QofQueryTerm *qt2)
01359 {
01360 if (qt1 == qt2) return TRUE;
01361 if (!qt1 || !qt2) return FALSE;
01362
01363 if (qt1->invert != qt2->invert) return FALSE;
01364 if (param_list_cmp (qt1->param_list, qt2->param_list)) return FALSE;
01365 return qof_query_core_predicate_equal (qt1->pdata, qt2->pdata);
01366 }
01367
01368 static gboolean
01369 qof_query_sort_equal (QofQuerySort* qs1, QofQuerySort* qs2)
01370 {
01371 if (qs1 == qs2) return TRUE;
01372 if (!qs1 || !qs2) return FALSE;
01373
01374
01375 if (!qs1->param_list && !qs2->param_list) return TRUE;
01376
01377 if (qs1->options != qs2->options) return FALSE;
01378 if (qs1->increasing != qs2->increasing) return FALSE;
01379 return (param_list_cmp (qs1->param_list, qs2->param_list) == 0);
01380 }
01381
01382 gboolean qof_query_equal (QofQuery *q1, QofQuery *q2)
01383 {
01384 GList *or1, *or2;
01385
01386 if (q1 == q2) return TRUE;
01387 if (!q1 || !q2) return FALSE;
01388
01389 if (g_list_length (q1->terms) != g_list_length (q2->terms)) return FALSE;
01390 if (q1->max_results != q2->max_results) return FALSE;
01391
01392 for (or1 = q1->terms, or2 = q2->terms; or1;
01393 or1 = or1->next, or2 = or2->next)
01394 {
01395 GList *and1, *and2;
01396
01397 and1 = or1->data;
01398 and2 = or2->data;
01399
01400 if (g_list_length (and1) != g_list_length (and2)) return FALSE;
01401
01402 for ( ; and1; and1 = and1->next, and2 = and2->next)
01403 if (!qof_query_term_equal (and1->data, and2->data))
01404 return FALSE;
01405 }
01406
01407 if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort)))
01408 return FALSE;
01409 if (!qof_query_sort_equal (&(q1->secondary_sort), &(q2->secondary_sort)))
01410 return FALSE;
01411 if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort)))
01412 return FALSE;
01413
01414 return TRUE;
01415 }
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425 static GList *qof_query_printSearchFor (QofQuery * query, GList * output);
01426 static GList *qof_query_printTerms (QofQuery * query, GList * output);
01427 static GList *qof_query_printSorts (QofQuerySort *s[], const gint numSorts,
01428 GList * output);
01429 static GList *qof_query_printAndTerms (GList * terms, GList * output);
01430 static gchar *qof_query_printStringForHow (QofQueryCompare how);
01431 static gchar *qof_query_printStringMatch (QofStringMatch s);
01432 static gchar *qof_query_printDateMatch (QofDateMatch d);
01433 static gchar *qof_query_printNumericMatch (QofNumericMatch n);
01434 static gchar *qof_query_printGuidMatch (QofGuidMatch g);
01435 static gchar *qof_query_printCharMatch (QofCharMatch c);
01436 static GString *qof_query_printPredData (QofQueryPredData *pd);
01437 static GString *qof_query_printParamPath (GSList * parmList);
01438 static void qof_query_printValueForParam (QofQueryPredData *pd, GString * gs);
01439 static void qof_query_printOutput (GList * output);
01440
01441
01442
01443
01444
01445 void
01446 qof_query_print (QofQuery * query)
01447 {
01448 GList *output;
01449 GString *str;
01450 QofQuerySort *s[3];
01451 gint maxResults = 0, numSorts = 3;
01452
01453 ENTER (" ");
01454
01455 if (!query) {
01456 LEAVE("query is (null)");
01457 return;
01458 }
01459
01460 output = NULL;
01461 str = NULL;
01462 maxResults = qof_query_get_max_results (query);
01463
01464 output = qof_query_printSearchFor (query, output);
01465 output = qof_query_printTerms (query, output);
01466
01467 qof_query_get_sorts (query, &s[0], &s[1], &s[2]);
01468
01469 if (s[0])
01470 {
01471 output = qof_query_printSorts (s, numSorts, output);
01472 }
01473
01474 str = g_string_new (" ");
01475 g_string_sprintf (str, "Maximum number of results: %d", maxResults);
01476 output = g_list_append (output, str);
01477
01478 qof_query_printOutput (output);
01479 LEAVE (" ");
01480 }
01481
01482 static void
01483 qof_query_printOutput (GList * output)
01484 {
01485 GList *lst;
01486
01487 for (lst = output; lst; lst = lst->next)
01488 {
01489 GString *line = (GString *) lst->data;
01490
01491 fprintf (stderr, "%s\n", line->str);
01492 g_string_free (line, TRUE);
01493 line = NULL;
01494 }
01495 }
01496
01497
01498
01499
01500
01501 static GList *
01502 qof_query_printSearchFor (QofQuery * query, GList * output)
01503 {
01504 QofIdType searchFor;
01505 GString *gs;
01506
01507 searchFor = qof_query_get_search_for (query);
01508 gs = g_string_new ("Query Object Type: ");
01509 g_string_append (gs, (NULL == searchFor)? "(null)" : searchFor);
01510 output = g_list_append (output, gs);
01511
01512 return output;
01513 }
01514
01515
01516
01517
01518
01519
01520 static GList *
01521 qof_query_printTerms (QofQuery * query, GList * output)
01522 {
01523
01524 GList *terms, *lst;
01525
01526 terms = qof_query_get_terms (query);
01527
01528 for (lst = terms; lst; lst = lst->next)
01529 {
01530 output = g_list_append (output, g_string_new ("OR and AND Terms:"));
01531
01532 if (lst->data)
01533 {
01534 output = qof_query_printAndTerms (lst->data, output);
01535 }
01536 else
01537 {
01538 output =
01539 g_list_append (output, g_string_new (" No data for AND terms"));
01540 }
01541 }
01542
01543 return output;
01544 }
01545
01546
01547
01548
01549
01550
01551 static GList *
01552 qof_query_printSorts (QofQuerySort *s[], const gint numSorts, GList * output)
01553 {
01554 GSList *gsl, *n = NULL;
01555 gint curSort;
01556 GString *gs = g_string_new (" Sort Parameters:\n");
01557
01558 for (curSort = 0; curSort < numSorts; curSort++)
01559 {
01560 gboolean increasing;
01561 if (!s[curSort])
01562 {
01563 break;
01564 }
01565 increasing = qof_query_sort_get_increasing (s[curSort]);
01566
01567 gsl = qof_query_sort_get_param_path (s[curSort]);
01568 if (gsl) g_string_sprintfa (gs, " Param: ");
01569 for (n=gsl; n; n = n->next)
01570 {
01571 QofIdType param_name = n->data;
01572 if (gsl != n)g_string_sprintfa (gs, "\n ");
01573 g_string_sprintfa (gs, "%s", param_name);
01574 }
01575 if (gsl)
01576 {
01577 g_string_sprintfa (gs, " %s\n", increasing ? "DESC" : "ASC");
01578 g_string_sprintfa (gs, " Options: 0x%x\n", s[curSort]->options);
01579 }
01580 }
01581
01582 output = g_list_append (output, gs);
01583 return output;
01584
01585 }
01586
01587
01588
01589
01590
01591 static GList *
01592 qof_query_printAndTerms (GList * terms, GList * output)
01593 {
01594 const char *prefix = " AND Terms:";
01595 QofQueryTerm *qt;
01596 QofQueryPredData *pd;
01597 GSList *path;
01598 GList *lst;
01599 gboolean invert;
01600
01601 output = g_list_append (output, g_string_new (prefix));
01602 for (lst = terms; lst; lst = lst->next)
01603 {
01604 qt = (QofQueryTerm *) lst->data;
01605 pd = qof_query_term_get_pred_data (qt);
01606 path = qof_query_term_get_param_path (qt);
01607 invert = qof_query_term_is_inverted (qt);
01608
01609 if (invert) output = g_list_append (output,
01610 g_string_new(" INVERT SENSE "));
01611 output = g_list_append (output, qof_query_printParamPath (path));
01612 output = g_list_append (output, qof_query_printPredData (pd));
01613 output = g_list_append (output, g_string_new("\n"));
01614 }
01615
01616 return output;
01617 }
01618
01619
01620
01621
01622 static GString *
01623 qof_query_printParamPath (GSList * parmList)
01624 {
01625 GSList *list = NULL;
01626 GString *gs = g_string_new (" Param List:\n");
01627 g_string_append (gs, " ");
01628 for (list = parmList; list; list = list->next)
01629 {
01630 g_string_append (gs, (gchar *) list->data);
01631 if (list->next)
01632 g_string_append (gs, "->");
01633 }
01634
01635 return gs;
01636 }
01637
01638
01639
01640
01641 static GString *
01642 qof_query_printPredData (QofQueryPredData *pd)
01643 {
01644 GString *gs;
01645
01646 gs = g_string_new (" Pred Data:\n ");
01647 g_string_append (gs, (gchar *) pd->type_name);
01648
01649
01650 if (safe_strcmp (pd->type_name, QOF_TYPE_CHAR) &&
01651 safe_strcmp (pd->type_name, QOF_TYPE_GUID))
01652 {
01653 g_string_sprintfa (gs, "\n how: %s",
01654 qof_query_printStringForHow (pd->how));
01655 }
01656
01657 qof_query_printValueForParam (pd, gs);
01658
01659 return gs;
01660 }
01661
01662
01663
01664
01665
01666 static gchar *
01667 qof_query_printStringForHow (QofQueryCompare how)
01668 {
01669
01670 switch (how)
01671 {
01672 case QOF_COMPARE_LT:
01673 return "QOF_COMPARE_LT";
01674 case QOF_COMPARE_LTE:
01675 return "QOF_COMPARE_LTE";
01676 case QOF_COMPARE_EQUAL:
01677 return "QOF_COMPARE_EQUAL";
01678 case QOF_COMPARE_GT:
01679 return "QOF_COMPARE_GT";
01680 case QOF_COMPARE_GTE:
01681 return "QOF_COMPARE_GTE";
01682 case QOF_COMPARE_NEQ:
01683 return "QOF_COMPARE_NEQ";
01684 }
01685
01686 return "INVALID HOW";
01687 }
01688
01689
01690 static void
01691 qof_query_printValueForParam (QofQueryPredData *pd, GString * gs)
01692 {
01693
01694 if (!safe_strcmp (pd->type_name, QOF_TYPE_GUID))
01695 {
01696 GList *node;
01697 query_guid_t pdata = (query_guid_t) pd;
01698 g_string_sprintfa (gs, "\n Match type %s",
01699 qof_query_printGuidMatch (pdata->options));
01700 for (node = pdata->guids; node; node = node->next)
01701 {
01702
01703 g_string_sprintfa (gs, ", guids: %s",
01704 guid_to_string ((GUID *) node->data));
01705 }
01706 return;
01707 }
01708 if (!safe_strcmp (pd->type_name, QOF_TYPE_STRING))
01709 {
01710 query_string_t pdata = (query_string_t) pd;
01711 g_string_sprintfa (gs, "\n Match type %s",
01712 qof_query_printStringMatch (pdata->options));
01713 g_string_sprintfa (gs, " %s string: %s",
01714 pdata->is_regex ? "Regex" : "Not regex",
01715 pdata->matchstring);
01716 return;
01717 }
01718 if (!safe_strcmp (pd->type_name, QOF_TYPE_NUMERIC))
01719 {
01720 query_numeric_t pdata = (query_numeric_t) pd;
01721 g_string_sprintfa (gs, "\n Match type %s",
01722 qof_query_printNumericMatch (pdata->options));
01723 g_string_sprintfa (gs, " gnc_numeric: %s",
01724 gnc_num_dbg_to_string (pdata->amount));
01725 return;
01726 }
01727 if (!safe_strcmp (pd->type_name, QOF_TYPE_KVP))
01728 {
01729 GSList *node;
01730 query_kvp_t pdata = (query_kvp_t) pd;
01731 g_string_sprintfa (gs, "\n kvp path: ");
01732 for (node = pdata->path; node; node = node->next)
01733 {
01734 g_string_sprintfa (gs, "/%s", (gchar *) node->data);
01735 }
01736 g_string_sprintfa (gs, "\n");
01737 g_string_sprintfa (gs, " kvp value: %s\n",
01738 kvp_value_to_string (pdata->value));
01739 return;
01740 }
01741 if (!safe_strcmp (pd->type_name, QOF_TYPE_INT64))
01742 {
01743 query_int64_t pdata = (query_int64_t) pd;
01744 g_string_sprintfa (gs, " int64: %" G_GINT64_FORMAT, pdata->val);
01745 return;
01746 }
01747 if (!safe_strcmp (pd->type_name, QOF_TYPE_INT32))
01748 {
01749 query_int32_t pdata = (query_int32_t) pd;
01750 g_string_sprintfa (gs, " int32: %d", pdata->val);
01751 return;
01752 }
01753 if (!safe_strcmp (pd->type_name, QOF_TYPE_DOUBLE))
01754 {
01755 query_double_t pdata = (query_double_t) pd;
01756 g_string_sprintfa (gs, " double: %.18g", pdata->val);
01757 return;
01758 }
01759 if (!safe_strcmp (pd->type_name, QOF_TYPE_DATE))
01760 {
01761 query_date_t pdata = (query_date_t) pd;
01762 g_string_sprintfa (gs, "\n Match type %s",
01763 qof_query_printDateMatch (pdata->options));
01764 g_string_sprintfa (gs, " query_date: %s", gnc_print_date (pdata->date));
01765 return;
01766 }
01767 if (!safe_strcmp (pd->type_name, QOF_TYPE_CHAR))
01768 {
01769 query_char_t pdata = (query_char_t) pd;
01770 g_string_sprintfa (gs, "\n Match type %s",
01771 qof_query_printCharMatch (pdata->options));
01772 g_string_sprintfa (gs, " char list: %s", pdata->char_list);
01773 return;
01774 }
01775 if (!safe_strcmp (pd->type_name, QOF_TYPE_BOOLEAN))
01776 {
01777 query_boolean_t pdata = (query_boolean_t) pd;
01778 g_string_sprintfa (gs, " boolean: %s", pdata->val?"TRUE":"FALSE");
01779 return;
01780 }
01782 return;
01783 }
01784
01785
01786
01787
01788
01789 static gchar *
01790 qof_query_printStringMatch (QofStringMatch s)
01791 {
01792 switch (s)
01793 {
01794 case QOF_STRING_MATCH_NORMAL:
01795 return "QOF_STRING_MATCH_NORMAL";
01796 case QOF_STRING_MATCH_CASEINSENSITIVE:
01797 return "QOF_STRING_MATCH_CASEINSENSITIVE";
01798 }
01799 return "UNKNOWN MATCH TYPE";
01800 }
01801
01802
01803
01804
01805
01806 static gchar *
01807 qof_query_printDateMatch (QofDateMatch d)
01808 {
01809 switch (d)
01810 {
01811 case QOF_DATE_MATCH_NORMAL:
01812 return "QOF_DATE_MATCH_NORMAL";
01813 case QOF_DATE_MATCH_DAY:
01814 return "QOF_DATE_MATCH_DAY";
01815 }
01816 return "UNKNOWN MATCH TYPE";
01817 }
01818
01819
01820
01821
01822
01823 static gchar *
01824 qof_query_printNumericMatch (QofNumericMatch n)
01825 {
01826 switch (n)
01827 {
01828 case QOF_NUMERIC_MATCH_DEBIT:
01829 return "QOF_NUMERIC_MATCH_DEBIT";
01830 case QOF_NUMERIC_MATCH_CREDIT:
01831 return "QOF_NUMERIC_MATCH_CREDIT";
01832 case QOF_NUMERIC_MATCH_ANY:
01833 return "QOF_NUMERIC_MATCH_ANY";
01834 }
01835 return "UNKNOWN MATCH TYPE";
01836 }
01837
01838
01839
01840
01841
01842 static gchar *
01843 qof_query_printGuidMatch (QofGuidMatch g)
01844 {
01845 switch (g)
01846 {
01847 case QOF_GUID_MATCH_ANY:
01848 return "QOF_GUID_MATCH_ANY";
01849 case QOF_GUID_MATCH_ALL:
01850 return "QOF_GUID_MATCH_ALL";
01851 case QOF_GUID_MATCH_NONE:
01852 return "QOF_GUID_MATCH_NONE";
01853 case QOF_GUID_MATCH_NULL:
01854 return "QOF_GUID_MATCH_NULL";
01855 case QOF_GUID_MATCH_LIST_ANY:
01856 return "QOF_GUID_MATCH_LIST_ANY";
01857 }
01858
01859 return "UNKNOWN MATCH TYPE";
01860 }
01861
01862
01863
01864
01865
01866 static gchar *
01867 qof_query_printCharMatch (QofCharMatch c)
01868 {
01869 switch (c)
01870 {
01871 case QOF_CHAR_MATCH_ANY:
01872 return "QOF_CHAR_MATCH_ANY";
01873 case QOF_CHAR_MATCH_NONE:
01874 return "QOF_CHAR_MATCH_NONE";
01875 }
01876 return "UNKNOWN MATCH TYPE";
01877 }
01878
01879