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 <ctype.h>
00027 #include <glib.h>
00028 #include <math.h>
00029 #include <string.h>
00030 #include <sys/types.h>
00031
00032 #include <regex.h>
00033 #include <sys/time.h>
00034 #include <unistd.h>
00035
00036 #include "gnc-lot.h"
00037 #include "Account.h"
00038 #include "Query.h"
00039 #include "Transaction.h"
00040 #include "TransactionP.h"
00041
00042 static QofLogModule log_module = GNC_MOD_QUERY;
00043
00044 static GSList *
00045 build_param_list_internal (const char *first, va_list rest)
00046 {
00047 GSList *list = NULL;
00048 char const *param;
00049
00050 for (param = first; param; param = va_arg (rest, const char *))
00051 list = g_slist_prepend (list, (gpointer)param);
00052
00053 return (g_slist_reverse (list));
00054 }
00055
00056
00057
00058
00059
00060
00061 SplitList *
00062 xaccQueryGetSplitsUniqueTrans(Query *q)
00063 {
00064 GList * splits = xaccQueryGetSplits(q);
00065 GList * current;
00066 GList * result = NULL;
00067 GHashTable * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
00068
00069 for (current = splits; current; current = current->next)
00070 {
00071 Split *split = current->data;
00072 Transaction *trans = xaccSplitGetParent (split);
00073
00074 if (!g_hash_table_lookup (trans_hash, trans))
00075 {
00076 g_hash_table_insert (trans_hash, trans, trans);
00077 result = g_list_prepend (result, split);
00078 }
00079 }
00080
00081 g_hash_table_destroy (trans_hash);
00082
00083 return g_list_reverse (result);
00084 }
00085
00086
00087
00088
00089
00090
00091
00092 static void
00093 query_match_all_filter_func(gpointer key, gpointer value, gpointer user_data)
00094 {
00095 Transaction * t = key;
00096 int num_matches = GPOINTER_TO_INT(value);
00097 GList ** matches = user_data;
00098
00099 if(num_matches == xaccTransCountSplits(t)) {
00100 *matches = g_list_prepend(*matches, t);
00101 }
00102 }
00103
00104 static void
00105 query_match_any_filter_func(gpointer key, gpointer value, gpointer user_data)
00106 {
00107 Transaction * t = key;
00108 GList ** matches = user_data;
00109 *matches = g_list_prepend(*matches, t);
00110 }
00111
00112 TransList *
00113 xaccQueryGetTransactions (Query * q, query_txn_match_t runtype)
00114 {
00115 GList * splits = xaccQueryGetSplits(q);
00116 GList * current = NULL;
00117 GList * retval = NULL;
00118 GHashTable * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
00119 Transaction * trans = NULL;
00120 gpointer val = NULL;
00121 int count = 0;
00122
00123
00124
00125 for(current = splits; current; current=current->next) {
00126 trans = xaccSplitGetParent((Split *)(current->data));
00127
00128
00129
00130 if(runtype == QUERY_TXN_MATCH_ALL) {
00131 val = g_hash_table_lookup(trans_hash, trans);
00132 count = GPOINTER_TO_INT(val);
00133 }
00134 g_hash_table_insert(trans_hash, trans, GINT_TO_POINTER(count + 1));
00135 }
00136
00137
00138 if(runtype == QUERY_TXN_MATCH_ALL) {
00139 g_hash_table_foreach(trans_hash, query_match_all_filter_func,
00140 &retval);
00141 }
00142 else {
00143 g_hash_table_foreach(trans_hash, query_match_any_filter_func,
00144 &retval);
00145 }
00146
00147 g_hash_table_destroy(trans_hash);
00148
00149 return retval;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158 static void
00159 query_match_all_lot_filter_func(gpointer key, gpointer value, gpointer user_data)
00160 {
00161 GNCLot * l = key;
00162 int num_matches = GPOINTER_TO_INT(value);
00163 GList ** matches = user_data;
00164
00165 if(num_matches == gnc_lot_count_splits(l)) {
00166 *matches = g_list_prepend(*matches, l);
00167 }
00168 }
00169
00170 static void
00171 query_match_any_lot_filter_func(gpointer key, gpointer value, gpointer user_data)
00172 {
00173 GNCLot * t = key;
00174 GList ** matches = user_data;
00175 *matches = g_list_prepend(*matches, t);
00176 }
00177
00178 LotList *
00179 xaccQueryGetLots (Query * q, query_txn_match_t runtype)
00180 {
00181 GList * splits = xaccQueryGetSplits(q);
00182 GList * current = NULL;
00183 GList * retval = NULL;
00184 GHashTable * lot_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
00185 GNCLot * lot = NULL;
00186 gpointer val = NULL;
00187 int count = 0;
00188
00189
00190
00191 for(current = splits; current; current=current->next) {
00192 lot = xaccSplitGetLot((Split *)(current->data));
00193
00194
00195
00196 if(runtype == QUERY_TXN_MATCH_ALL) {
00197 val = g_hash_table_lookup(lot_hash, lot);
00198 count = GPOINTER_TO_INT(val);
00199 }
00200 g_hash_table_insert(lot_hash, lot, GINT_TO_POINTER(count + 1));
00201 }
00202
00203
00204 if(runtype == QUERY_TXN_MATCH_ALL) {
00205 g_hash_table_foreach(lot_hash, query_match_all_lot_filter_func,
00206 &retval);
00207 }
00208 else {
00209 g_hash_table_foreach(lot_hash, query_match_any_lot_filter_func,
00210 &retval);
00211 }
00212
00213 g_hash_table_destroy(lot_hash);
00214
00215 return retval;
00216 }
00217
00218
00219
00220
00221
00222 void
00223 xaccQueryAddAccountMatch(Query *q, AccountList *acct_list,
00224 QofGuidMatch how, QofQueryOp op)
00225 {
00226 GList *list = NULL;
00227
00228 if (!q) return;
00229 for (; acct_list; acct_list = acct_list->next) {
00230 Account *acc = acct_list->data;
00231 const GUID *guid;
00232
00233 if (!acc) {
00234 PWARN ("acct_list has NULL account");
00235 continue;
00236 }
00237
00238 guid = xaccAccountGetGUID (acc);
00239 if (!guid) {
00240 PWARN ("acct returns NULL GUID");
00241 continue;
00242 }
00243
00244 list = g_list_prepend (list, (gpointer)guid);
00245 }
00246 xaccQueryAddAccountGUIDMatch (q, list, how, op);
00247 g_list_free (list);
00248 }
00249
00250 void
00251 xaccQueryAddAccountGUIDMatch(Query *q, AccountGUIDList *guid_list,
00252 QofGuidMatch how, QofQueryOp op)
00253 {
00254 QofQueryPredData *pred_data;
00255 GSList *param_list = NULL;
00256
00257 if (!q) return;
00258
00259 pred_data = qof_query_guid_predicate (how, guid_list);
00260 if (!pred_data)
00261 return;
00262
00263 switch (how) {
00264 case QOF_GUID_MATCH_ANY:
00265 case QOF_GUID_MATCH_NONE:
00266 param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, NULL);
00267 break;
00268 case QOF_GUID_MATCH_ALL:
00269 param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_SPLITLIST,
00270 SPLIT_ACCOUNT_GUID, NULL);
00271 break;
00272 default:
00273 PERR ("Invalid match type: %d", how);
00274 }
00275
00276 qof_query_add_term (q, param_list, pred_data, op);
00277 }
00278
00279 void
00280 xaccQueryAddSingleAccountMatch(Query *q, Account *acc, QofQueryOp op)
00281 {
00282 GList *list;
00283 const GUID *guid;
00284
00285 if (!q || !acc)
00286 return;
00287
00288 guid = xaccAccountGetGUID (acc);
00289 g_return_if_fail (guid);
00290
00291 list = g_list_prepend (NULL, (gpointer)guid);
00292 xaccQueryAddAccountGUIDMatch (q, list, QOF_GUID_MATCH_ANY, op);
00293 g_list_free (list);
00294 }
00295
00296 void
00297 xaccQueryAddStringMatch (Query* q, const char *matchstring,
00298 gboolean case_sens, gboolean use_regexp,
00299 QofQueryOp op,
00300 const char * path, ...)
00301 {
00302 QofQueryPredData *pred_data;
00303 GSList *param_list;
00304 va_list ap;
00305
00306 if (!path || !q)
00307 return;
00308
00309 pred_data = qof_query_string_predicate (QOF_COMPARE_EQUAL, (char *)matchstring,
00310 (case_sens ? QOF_STRING_MATCH_NORMAL :
00311 QOF_STRING_MATCH_CASEINSENSITIVE),
00312 use_regexp);
00313 if (!pred_data)
00314 return;
00315
00316 va_start (ap, path);
00317 param_list = build_param_list_internal (path, ap);
00318 va_end (ap);
00319
00320 qof_query_add_term (q, param_list, pred_data, op);
00321 }
00322
00323 void
00324 xaccQueryAddNumericMatch (Query *q, gnc_numeric amount, QofNumericMatch sign,
00325 QofQueryCompare how, QofQueryOp op,
00326 const char * path, ...)
00327 {
00328 QofQueryPredData *pred_data;
00329 GSList *param_list;
00330 va_list ap;
00331
00332 if (!q || !path)
00333 return;
00334
00335 pred_data = qof_query_numeric_predicate (how, sign, amount);
00336 if (!pred_data)
00337 return;
00338
00339 va_start (ap, path);
00340 param_list = build_param_list_internal (path, ap);
00341 va_end (ap);
00342
00343 qof_query_add_term (q, param_list, pred_data, op);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 void
00356 xaccQueryAddDateMatchTS (Query * q,
00357 gboolean use_start, Timespec sts,
00358 gboolean use_end, Timespec ets,
00359 QofQueryOp op)
00360 {
00361 Query *tmp_q = NULL;
00362 QofQueryPredData *pred_data;
00363 GSList *param_list;
00364
00365 if (!q || (!use_start && !use_end))
00366 return;
00367
00368 tmp_q = qof_query_create ();
00369
00370 if (use_start) {
00371 pred_data = qof_query_date_predicate (QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, sts);
00372 if (!pred_data) {
00373 qof_query_destroy (tmp_q);
00374 return;
00375 }
00376
00377 param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, NULL);
00378 qof_query_add_term (tmp_q, param_list, pred_data, QOF_QUERY_AND);
00379 }
00380
00381 if (use_end) {
00382 pred_data = qof_query_date_predicate (QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, ets);
00383 if (!pred_data) {
00384 qof_query_destroy (tmp_q);
00385 return;
00386 }
00387
00388 param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, NULL);
00389 qof_query_add_term (tmp_q, param_list, pred_data, QOF_QUERY_AND);
00390 }
00391
00392 qof_query_merge_in_place (q, tmp_q, op);
00393 qof_query_destroy (tmp_q);
00394 }
00395
00396 void
00397 xaccQueryGetDateMatchTS (Query * q,
00398 Timespec * sts,
00399 Timespec * ets)
00400 {
00401 QofQueryPredData *term_data;
00402 GSList *param_list;
00403 GSList *terms, *tmp;
00404
00405 sts->tv_sec = sts->tv_nsec = 0;
00406 ets->tv_sec = ets->tv_nsec = 0;
00407
00408 param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, NULL);
00409 terms = qof_query_get_term_type (q, param_list);
00410 g_slist_free(param_list);
00411
00412 for (tmp = terms; tmp; tmp = g_slist_next(tmp)) {
00413 term_data = tmp->data;
00414 if (term_data->how == QOF_COMPARE_GTE)
00415 qof_query_date_predicate_get_date(term_data, sts);
00416 if (term_data->how == QOF_COMPARE_LTE)
00417 qof_query_date_predicate_get_date(term_data, ets);
00418 }
00419 g_slist_free(terms);
00420 }
00421
00422
00423
00424
00425
00426
00427 void
00428 xaccQueryAddDateMatch(Query * q,
00429 gboolean use_start, int sday, int smonth, int syear,
00430 gboolean use_end, int eday, int emonth, int eyear,
00431 QofQueryOp op)
00432 {
00433
00434 xaccQueryAddDateMatchTS (q, use_start,
00435 gnc_dmy2timespec(sday, smonth, syear),
00436 use_end,
00437 gnc_dmy2timespec_end(eday, emonth, eyear),
00438 op);
00439 }
00440
00441
00442
00443
00444
00445
00446 void
00447 xaccQueryAddDateMatchTT(Query * q,
00448 gboolean use_start,
00449 time_t stt,
00450 gboolean use_end,
00451 time_t ett,
00452 QofQueryOp op)
00453 {
00454 Timespec sts;
00455 Timespec ets;
00456
00457 sts.tv_sec = (long long)stt;
00458 sts.tv_nsec = 0;
00459
00460 ets.tv_sec = (long long)ett;
00461 ets.tv_nsec = 0;
00462
00463
00464 xaccQueryAddDateMatchTS (q, use_start, sts,
00465 use_end, ets, op);
00466
00467 }
00468
00469 void
00470 xaccQueryGetDateMatchTT (Query * q,
00471 time_t * stt,
00472 time_t * ett)
00473 {
00474 Timespec sts;
00475 Timespec ets;
00476
00477 xaccQueryGetDateMatchTS (q, &sts, &ets);
00478
00479 *stt = sts.tv_sec;
00480 *ett = ets.tv_sec;
00481 }
00482
00483 void
00484 xaccQueryAddClearedMatch(Query * q, cleared_match_t how, QofQueryOp op)
00485 {
00486 QofQueryPredData *pred_data;
00487 GSList *param_list;
00488 char chars[6];
00489 int i = 0;
00490
00491 if (!q)
00492 return;
00493
00494 if (how & CLEARED_CLEARED)
00495 chars[i++] = CREC;
00496 if (how & CLEARED_RECONCILED)
00497 chars[i++] = YREC;
00498 if (how & CLEARED_FROZEN)
00499 chars[i++] = FREC;
00500 if (how & CLEARED_NO)
00501 chars[i++] = NREC;
00502 if (how & CLEARED_VOIDED)
00503 chars[i++] = VREC;
00504 chars[i] = '\0';
00505
00506 pred_data = qof_query_char_predicate (QOF_CHAR_MATCH_ANY, chars);
00507 if (!pred_data)
00508 return;
00509
00510 param_list = qof_query_build_param_list (SPLIT_RECONCILE, NULL);
00511
00512 qof_query_add_term (q, param_list, pred_data, op);
00513 }
00514
00515 void
00516 xaccQueryAddGUIDMatch(Query * q, const GUID *guid,
00517 QofIdType id_type, QofQueryOp op)
00518 {
00519 GSList *param_list = NULL;
00520
00521 if (!q || !guid || !id_type)
00522 return;
00523
00524 if (!safe_strcmp (id_type, GNC_ID_SPLIT))
00525 param_list = qof_query_build_param_list (QOF_PARAM_GUID, NULL);
00526 else if (!safe_strcmp (id_type, GNC_ID_TRANS))
00527 param_list = qof_query_build_param_list (SPLIT_TRANS, QOF_PARAM_GUID, NULL);
00528 else if (!safe_strcmp (id_type, GNC_ID_ACCOUNT))
00529 param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, NULL);
00530 else
00531 PERR ("Invalid match type: %s", id_type);
00532
00533 qof_query_add_guid_match (q, param_list, guid, op);
00534 }
00535
00536 void
00537 xaccQueryAddKVPMatch(QofQuery *q, GSList *path, const KvpValue *value,
00538 QofQueryCompare how, QofIdType id_type,
00539 QofQueryOp op)
00540 {
00541 GSList *param_list = NULL;
00542 QofQueryPredData *pred_data;
00543
00544 if (!q || !path || !value || !id_type)
00545 return;
00546
00547 pred_data = qof_query_kvp_predicate (how, path, value);
00548 if (!pred_data)
00549 return;
00550
00551 if (!safe_strcmp (id_type, GNC_ID_SPLIT))
00552 param_list = qof_query_build_param_list (SPLIT_KVP, NULL);
00553 else if (!safe_strcmp (id_type, GNC_ID_TRANS))
00554 param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_KVP, NULL);
00555 else if (!safe_strcmp (id_type, GNC_ID_ACCOUNT))
00556 param_list = qof_query_build_param_list (SPLIT_ACCOUNT, ACCOUNT_KVP, NULL);
00557 else
00558 PERR ("Invalid match type: %s", id_type);
00559
00560 qof_query_add_term (q, param_list, pred_data, op);
00561 }
00562
00563
00564
00565
00566
00567 time_t
00568 xaccQueryGetEarliestDateFound(Query * q)
00569 {
00570 GList * spl;
00571 Split * sp;
00572 time_t earliest;
00573
00574 if (!q) return 0;
00575 spl = qof_query_last_run (q);
00576 if (!spl) return 0;
00577
00578
00579 sp = spl->data;
00580 earliest = (time_t) sp->parent->date_posted.tv_sec;
00581 for(; spl; spl=spl->next) {
00582 sp = spl->data;
00583 if(sp->parent->date_posted.tv_sec < earliest) {
00584 earliest = (time_t) sp->parent->date_posted.tv_sec;
00585 }
00586 }
00587 return earliest;
00588 }
00589
00590
00591
00592
00593
00594 time_t
00595 xaccQueryGetLatestDateFound(Query * q)
00596 {
00597 Split * sp;
00598 GList * spl;
00599 time_t latest = 0;
00600
00601 if(!q) return 0;
00602 spl = qof_query_last_run (q);
00603 if(!spl) return 0;
00604
00605 for(; spl; spl=spl->next) {
00606 sp = spl->data;
00607 if(sp->parent->date_posted.tv_sec > latest) {
00608 latest = (time_t) sp->parent->date_posted.tv_sec;
00609 }
00610 }
00611 return latest;
00612 }
00613
00614 void
00615 xaccQueryAddDescriptionMatch(Query *q, const char *m, gboolean c, gboolean r,
00616 QofQueryOp o)
00617 {
00618 xaccQueryAddStringMatch ((q), (m), (c), (r), (o), SPLIT_TRANS,
00619 TRANS_DESCRIPTION, NULL);
00620 }
00621
00622 void
00623 xaccQueryAddNumberMatch(Query *q, const char *m, gboolean c, gboolean r,
00624 QofQueryOp o)
00625 {
00626 xaccQueryAddStringMatch ((q), (m), (c), (r), (o), SPLIT_TRANS,
00627 TRANS_NUM, NULL);
00628 }
00629
00630 void
00631 xaccQueryAddActionMatch(Query *q, const char *m, gboolean c, gboolean r,
00632 QofQueryOp o)
00633 {
00634 xaccQueryAddStringMatch ((q), (m), (c), (r), (o), SPLIT_ACTION, NULL);
00635 }
00636
00637 void
00638 xaccQueryAddMemoMatch(Query *q, const char *m, gboolean c, gboolean r,
00639 QofQueryOp o)
00640 {
00641 xaccQueryAddStringMatch ((q), (m), (c), (r), (o), SPLIT_MEMO, NULL);
00642 }
00643
00644 void
00645 xaccQueryAddValueMatch(Query *q, gnc_numeric amt, QofNumericMatch sgn,
00646 QofQueryCompare how, QofQueryOp op)
00647 {
00648 xaccQueryAddNumericMatch ((q), (amt), (sgn), (how), (op),
00649 SPLIT_VALUE, NULL);
00650 }
00651
00652 void
00653 xaccQueryAddSharePriceMatch(Query *q, gnc_numeric amt, QofQueryCompare how,
00654 QofQueryOp op)
00655 {
00656 xaccQueryAddNumericMatch ((q), (amt), QOF_NUMERIC_MATCH_ANY, (how), (op),
00657 SPLIT_SHARE_PRICE, NULL);
00658 }
00659
00660 void
00661 xaccQueryAddSharesMatch(Query *q, gnc_numeric amt, QofQueryCompare how,
00662 QofQueryOp op)
00663 {
00664 xaccQueryAddNumericMatch ((q), (amt), QOF_NUMERIC_MATCH_ANY, (how), (op),
00665 SPLIT_AMOUNT, NULL);
00666 }
00667
00668 void
00669 xaccQueryAddBalanceMatch(Query *q, QofQueryCompare bal, QofQueryOp op)
00670 {
00671 xaccQueryAddNumericMatch(
00672 (q), gnc_numeric_zero(), QOF_NUMERIC_MATCH_ANY,
00673 ((bal) ? QOF_COMPARE_EQUAL : QOF_COMPARE_NEQ), (op),
00674 SPLIT_TRANS, TRANS_IMBALANCE, NULL);
00675 }
00676
00677
00678