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