Branch data Line data Source code
1 : : /********************************************************************\
2 : : * Query.c : api for finding transactions *
3 : : * Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
4 : : * Copyright (C) 2002 Linas Vepstas <linas@linas.org> *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License*
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : \********************************************************************/
23 : :
24 : : #include <config.h>
25 : :
26 : : #include <platform.h>
27 : : #if PLATFORM(WINDOWS)
28 : : #include <windows.h>
29 : : #endif
30 : :
31 : : #include <ctype.h>
32 : : #include <glib.h>
33 : : #include <math.h>
34 : : #include <string.h>
35 : : #include <sys/types.h>
36 : :
37 : : #include <regex.h>
38 : : #ifdef HAVE_UNISTD_H
39 : : # include <unistd.h>
40 : : #endif
41 : :
42 : : #include "gnc-lot.h"
43 : : #include "Account.h"
44 : : #include "Query.h"
45 : : #include "Transaction.h"
46 : : #include "TransactionP.hpp"
47 : :
48 : : static QofLogModule log_module = GNC_MOD_QUERY;
49 : :
50 : : static GSList *
51 : 2413 : build_param_list_internal (const char *first, va_list rest)
52 : : {
53 : 2413 : GSList *list = nullptr;
54 : : char const *param;
55 : :
56 : 5627 : for (param = first; param; param = va_arg (rest, const char *))
57 : 3214 : list = g_slist_prepend (list, (gpointer)param);
58 : :
59 : 2413 : return (g_slist_reverse (list));
60 : : }
61 : :
62 : : /********************************************************************
63 : : * xaccQueryGetSplitsUniqueTrans
64 : : * Get splits but no more than one from a given transaction.
65 : : ********************************************************************/
66 : :
67 : : SplitList *
68 : 32 : xaccQueryGetSplitsUniqueTrans(QofQuery *q)
69 : : {
70 : 32 : GList * splits = qof_query_run(q);
71 : : GList * current;
72 : 32 : GList * result = nullptr;
73 : 32 : GHashTable * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
74 : :
75 : 658 : for (current = splits; current; current = current->next)
76 : : {
77 : 626 : Split *split = GNC_SPLIT (current->data);
78 : 626 : Transaction *trans = xaccSplitGetParent (split);
79 : :
80 : 626 : if (!g_hash_table_lookup (trans_hash, trans))
81 : : {
82 : 459 : g_hash_table_insert (trans_hash, trans, trans);
83 : 459 : result = g_list_prepend (result, split);
84 : : }
85 : : }
86 : :
87 : 32 : g_hash_table_destroy (trans_hash);
88 : :
89 : 32 : return g_list_reverse (result);
90 : : }
91 : :
92 : : /********************************************************************
93 : : * xaccQueryGetTransactions
94 : : * Get transactions matching the query terms, specifying whether
95 : : * we require some or all splits to match
96 : : ********************************************************************/
97 : :
98 : : static void
99 : 59 : query_match_all_filter_func(gpointer key, gpointer value, gpointer user_data)
100 : : {
101 : 59 : Transaction * t = GNC_TRANSACTION(key);
102 : 59 : int num_matches = GPOINTER_TO_INT(value);
103 : 59 : auto matches = static_cast<GList**>(user_data);
104 : :
105 : 59 : if (num_matches == xaccTransCountSplits(t))
106 : : {
107 : 59 : *matches = g_list_prepend(*matches, t);
108 : : }
109 : 59 : }
110 : :
111 : : static void
112 : 200 : query_match_any_filter_func(gpointer key, gpointer value, gpointer user_data)
113 : : {
114 : 200 : Transaction * t = GNC_TRANSACTION(key);
115 : 200 : auto matches = static_cast<GList**>(user_data);
116 : 200 : *matches = g_list_prepend(*matches, t);
117 : 200 : }
118 : :
119 : : TransList *
120 : 201 : xaccQueryGetTransactions (QofQuery * q, query_txn_match_t runtype)
121 : : {
122 : 201 : GList * splits = qof_query_run(q);
123 : 201 : GList * current = nullptr;
124 : 201 : GList * retval = nullptr;
125 : 201 : GHashTable * trans_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
126 : 201 : Transaction * trans = nullptr;
127 : 201 : gpointer val = nullptr;
128 : 201 : int count = 0;
129 : :
130 : : /* iterate over matching splits, incrementing a match-count in
131 : : * the hash table */
132 : 520 : for (current = splits; current; current = current->next)
133 : : {
134 : 319 : trans = xaccSplitGetParent(GNC_SPLIT(current->data));
135 : :
136 : : /* don't waste time looking up unless we need the count
137 : : * information */
138 : 319 : if (runtype == QUERY_TXN_MATCH_ALL)
139 : : {
140 : 119 : val = g_hash_table_lookup(trans_hash, trans);
141 : 119 : count = GPOINTER_TO_INT(val);
142 : : }
143 : 319 : g_hash_table_insert(trans_hash, trans, GINT_TO_POINTER(count + 1));
144 : : }
145 : :
146 : : /* now pick out the transactions that match */
147 : 201 : if (runtype == QUERY_TXN_MATCH_ALL)
148 : : {
149 : 1 : g_hash_table_foreach(trans_hash, query_match_all_filter_func,
150 : : &retval);
151 : : }
152 : : else
153 : : {
154 : 200 : g_hash_table_foreach(trans_hash, query_match_any_filter_func,
155 : : &retval);
156 : : }
157 : :
158 : 201 : g_hash_table_destroy(trans_hash);
159 : :
160 : 201 : return retval;
161 : : }
162 : :
163 : : /********************************************************************
164 : : * xaccQueryGetLots
165 : : * Get lots matching the query terms, specifying whether
166 : : * we require some or all splits to match
167 : : ********************************************************************/
168 : :
169 : : static void
170 : 0 : query_match_all_lot_filter_func(gpointer key, gpointer value, gpointer user_data)
171 : : {
172 : 0 : GNCLot * l = GNC_LOT(key);
173 : 0 : int num_matches = GPOINTER_TO_INT(value);
174 : 0 : auto matches = static_cast<GList**>(user_data);
175 : :
176 : 0 : if (num_matches == gnc_lot_count_splits(l))
177 : : {
178 : 0 : *matches = g_list_prepend(*matches, l);
179 : : }
180 : 0 : }
181 : :
182 : : static void
183 : 0 : query_match_any_lot_filter_func(gpointer key, gpointer value, gpointer user_data)
184 : : {
185 : 0 : GNCLot * t = GNC_LOT(key);
186 : 0 : auto matches = static_cast<GList**>(user_data);
187 : 0 : *matches = g_list_prepend(*matches, t);
188 : 0 : }
189 : :
190 : : LotList *
191 : 0 : xaccQueryGetLots (QofQuery * q, query_txn_match_t runtype)
192 : : {
193 : 0 : GList * splits = qof_query_run(q);
194 : 0 : GList * current = nullptr;
195 : 0 : GList * retval = nullptr;
196 : 0 : GHashTable * lot_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
197 : 0 : GNCLot * lot = nullptr;
198 : 0 : gpointer val = nullptr;
199 : 0 : int count = 0;
200 : :
201 : : /* iterate over matching splits, incrementing a match-count in
202 : : * the hash table */
203 : 0 : for (current = splits; current; current = current->next)
204 : : {
205 : 0 : lot = xaccSplitGetLot((GNC_SPLIT (current->data)));
206 : :
207 : : /* don't waste time looking up unless we need the count
208 : : * information */
209 : 0 : if (runtype == QUERY_TXN_MATCH_ALL)
210 : : {
211 : 0 : val = g_hash_table_lookup(lot_hash, lot);
212 : 0 : count = GPOINTER_TO_INT(val);
213 : : }
214 : 0 : g_hash_table_insert(lot_hash, lot, GINT_TO_POINTER(count + 1));
215 : : }
216 : :
217 : : /* now pick out the transactions that match */
218 : 0 : if (runtype == QUERY_TXN_MATCH_ALL)
219 : : {
220 : 0 : g_hash_table_foreach(lot_hash, query_match_all_lot_filter_func,
221 : : &retval);
222 : : }
223 : : else
224 : : {
225 : 0 : g_hash_table_foreach(lot_hash, query_match_any_lot_filter_func,
226 : : &retval);
227 : : }
228 : :
229 : 0 : g_hash_table_destroy(lot_hash);
230 : :
231 : 0 : return retval;
232 : : }
233 : :
234 : : /*******************************************************************
235 : : * match-adding API
236 : : *******************************************************************/
237 : :
238 : : void
239 : 2082 : xaccQueryAddAccountMatch(QofQuery *q, AccountList *acct_list,
240 : : QofGuidMatch how, QofQueryOp op)
241 : : {
242 : 2082 : GList *list = nullptr;
243 : :
244 : 2082 : if (!q) return;
245 : 15169 : for (; acct_list; acct_list = acct_list->next)
246 : : {
247 : 13087 : Account *acc = GNC_ACCOUNT (acct_list->data);
248 : : const GncGUID *guid;
249 : :
250 : 13087 : if (!acc)
251 : : {
252 : 0 : PWARN ("acct_list has nullptr account");
253 : 0 : continue;
254 : : }
255 : :
256 : 13087 : guid = qof_entity_get_guid (QOF_INSTANCE(acc));
257 : 13087 : if (!guid)
258 : : {
259 : 0 : PWARN ("acct returns nullptr GncGUID");
260 : 0 : continue;
261 : : }
262 : :
263 : 13087 : list = g_list_prepend (list, (gpointer)guid);
264 : : }
265 : 2082 : xaccQueryAddAccountGUIDMatch (q, list, how, op);
266 : 2082 : g_list_free (list);
267 : : }
268 : :
269 : : void
270 : 2888 : xaccQueryAddAccountGUIDMatch(QofQuery *q, AccountGUIDList *guid_list,
271 : : QofGuidMatch how, QofQueryOp op)
272 : : {
273 : : QofQueryPredData *pred_data;
274 : 2888 : GSList *param_list = nullptr;
275 : :
276 : 2888 : if (!q) return;
277 : :
278 : 2888 : if (!guid_list && how != QOF_GUID_MATCH_NULL)
279 : : {
280 : 3 : g_warning("Got a nullptr guid_list but the QofGuidMatch is not MATCH_nullptr (but instead %d). In other words, the list of GUID matches is empty but it must contain something non-empty.", how);
281 : : /* qof_query_guid_predicate() would trigger a g_warning as well */
282 : 3 : return;
283 : : }
284 : 2885 : pred_data = qof_query_guid_predicate (how, guid_list);
285 : 2885 : if (!pred_data)
286 : 0 : return;
287 : :
288 : 2885 : switch (how)
289 : : {
290 : 2685 : case QOF_GUID_MATCH_ANY:
291 : : case QOF_GUID_MATCH_NONE:
292 : 2685 : param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, nullptr);
293 : 2685 : break;
294 : 200 : case QOF_GUID_MATCH_ALL:
295 : 200 : param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_SPLITLIST,
296 : : SPLIT_ACCOUNT_GUID, nullptr);
297 : 200 : break;
298 : 0 : default:
299 : 0 : PERR ("Invalid match type: %d", how);
300 : 0 : break;
301 : : }
302 : :
303 : 2885 : qof_query_add_term (q, param_list, pred_data, op);
304 : : }
305 : :
306 : : void
307 : 207 : xaccQueryAddSingleAccountMatch(QofQuery *q, Account *acc, QofQueryOp op)
308 : : {
309 : : GList *list;
310 : : const GncGUID *guid;
311 : :
312 : 207 : if (!q || !acc)
313 : 2 : return;
314 : :
315 : 205 : guid = qof_entity_get_guid (QOF_INSTANCE(acc));
316 : 205 : g_return_if_fail (guid);
317 : :
318 : 205 : list = g_list_prepend (nullptr, (gpointer)guid);
319 : 205 : xaccQueryAddAccountGUIDMatch (q, list, QOF_GUID_MATCH_ANY, op);
320 : 205 : g_list_free (list);
321 : : }
322 : :
323 : : void
324 : 1563 : xaccQueryAddStringMatch (QofQuery* q, const char *matchstring,
325 : : gboolean case_sens, gboolean use_regexp,
326 : : QofQueryCompare how, QofQueryOp op,
327 : : const char * path, ...)
328 : : {
329 : : QofQueryPredData *pred_data;
330 : : GSList *param_list;
331 : : va_list ap;
332 : :
333 : 1563 : if (!path || !q)
334 : 0 : return;
335 : :
336 : 1563 : pred_data = qof_query_string_predicate (how, (char *)matchstring,
337 : : (case_sens ? QOF_STRING_MATCH_NORMAL :
338 : : QOF_STRING_MATCH_CASEINSENSITIVE),
339 : : use_regexp);
340 : 1563 : if (!pred_data)
341 : 419 : return;
342 : :
343 : 1144 : va_start (ap, path);
344 : 1144 : param_list = build_param_list_internal (path, ap);
345 : 1144 : va_end (ap);
346 : :
347 : 1144 : qof_query_add_term (q, param_list, pred_data, op);
348 : : }
349 : :
350 : : void
351 : 1269 : xaccQueryAddNumericMatch (QofQuery *q, gnc_numeric amount, QofNumericMatch sign,
352 : : QofQueryCompare how, QofQueryOp op,
353 : : const char * path, ...)
354 : : {
355 : : QofQueryPredData *pred_data;
356 : : GSList *param_list;
357 : : va_list ap;
358 : :
359 : 1269 : if (!q || !path)
360 : 0 : return;
361 : :
362 : 1269 : pred_data = qof_query_numeric_predicate (how, sign, amount);
363 : 1269 : if (!pred_data)
364 : 0 : return;
365 : :
366 : 1269 : va_start (ap, path);
367 : 1269 : param_list = build_param_list_internal (path, ap);
368 : 1269 : va_end (ap);
369 : :
370 : 1269 : qof_query_add_term (q, param_list, pred_data, op);
371 : : }
372 : :
373 : : /* The DateMatch queries match transactions whose posted date
374 : : * is in a date range. If use_start is TRUE, then a matching
375 : : * posted date will be greater than the start date. If
376 : : * use_end is TRUE, then a match occurs for posted dates earlier
377 : : * than the end date. If both flags are set, then *both*
378 : : * conditions must hold ('and'). If neither flag is set, then
379 : : * all transactions are matched.
380 : : */
381 : :
382 : : void
383 : 2267 : xaccQueryAddDateMatchTT (QofQuery * q,
384 : : gboolean use_start, time64 stt,
385 : : gboolean use_end, time64 ett,
386 : : QofQueryOp op)
387 : : {
388 : 2267 : QofQuery *tmp_q = nullptr;
389 : : QofQueryPredData *pred_data;
390 : : GSList *param_list;
391 : :
392 : 2267 : if (!q || (!use_start && !use_end))
393 : 56 : return;
394 : :
395 : 2211 : tmp_q = qof_query_create ();
396 : :
397 : 2211 : if (use_start)
398 : : {
399 : 1642 : pred_data = qof_query_date_predicate (QOF_COMPARE_GTE, QOF_DATE_MATCH_NORMAL, stt);
400 : 1642 : if (!pred_data)
401 : : {
402 : 0 : qof_query_destroy (tmp_q);
403 : 0 : return;
404 : : }
405 : :
406 : 1642 : param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, nullptr);
407 : 1642 : qof_query_add_term (tmp_q, param_list, pred_data, QOF_QUERY_AND);
408 : : }
409 : :
410 : 2211 : if (use_end)
411 : : {
412 : 2172 : pred_data = qof_query_date_predicate (QOF_COMPARE_LTE, QOF_DATE_MATCH_NORMAL, ett);
413 : 2172 : if (!pred_data)
414 : : {
415 : 0 : qof_query_destroy (tmp_q);
416 : 0 : return;
417 : : }
418 : :
419 : 2172 : param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, nullptr);
420 : 2172 : qof_query_add_term (tmp_q, param_list, pred_data, QOF_QUERY_AND);
421 : : }
422 : :
423 : 2211 : qof_query_merge_in_place (q, tmp_q, op);
424 : 2211 : qof_query_destroy (tmp_q);
425 : : }
426 : :
427 : : void
428 : 0 : xaccQueryGetDateMatchTT (QofQuery * q,
429 : : time64 * stt,
430 : : time64 * ett)
431 : : {
432 : : QofQueryPredData *term_data;
433 : : GSList *param_list;
434 : : GSList *terms, *tmp;
435 : :
436 : 0 : *stt = 0;
437 : 0 : *ett = 0;
438 : :
439 : 0 : param_list = qof_query_build_param_list (SPLIT_TRANS, TRANS_DATE_POSTED, nullptr);
440 : 0 : terms = qof_query_get_term_type (q, param_list);
441 : 0 : g_slist_free(param_list);
442 : :
443 : 0 : for (tmp = terms; tmp; tmp = g_slist_next(tmp))
444 : : {
445 : 0 : term_data = static_cast<QofQueryPredData*>(tmp->data);
446 : 0 : if (term_data->how == QOF_COMPARE_GTE)
447 : 0 : qof_query_date_predicate_get_date(term_data, stt);
448 : 0 : if (term_data->how == QOF_COMPARE_LTE)
449 : 0 : qof_query_date_predicate_get_date(term_data, ett);
450 : : }
451 : 0 : g_slist_free(terms);
452 : 0 : }
453 : :
454 : : /********************************************************************
455 : : * xaccQueryAddDateMatch
456 : : * Add a date filter to an existing query.
457 : : ********************************************************************/
458 : :
459 : : void
460 : 0 : xaccQueryAddDateMatch(QofQuery * q,
461 : : gboolean use_start, int sday, int smonth, int syear,
462 : : gboolean use_end, int eday, int emonth, int eyear,
463 : : QofQueryOp op)
464 : : {
465 : : /* gcc -O3 will auto-inline this function, avoiding a call overhead */
466 : 0 : xaccQueryAddDateMatchTT (q, use_start,
467 : : gnc_dmy2time64(sday, smonth, syear),
468 : : use_end,
469 : : gnc_dmy2time64_end(eday, emonth, eyear),
470 : : op);
471 : 0 : }
472 : :
473 : : void
474 : 1828 : xaccQueryAddClearedMatch(QofQuery * q, cleared_match_t how, QofQueryOp op)
475 : : {
476 : : QofQueryPredData *pred_data;
477 : : GSList *param_list;
478 : : char chars[6];
479 : 1828 : int i = 0;
480 : :
481 : 1828 : if (!q)
482 : 0 : return;
483 : :
484 : 1828 : if (how & CLEARED_CLEARED)
485 : 1600 : chars[i++] = CREC;
486 : 1828 : if (how & CLEARED_RECONCILED)
487 : 1572 : chars[i++] = YREC;
488 : 1828 : if (how & CLEARED_FROZEN)
489 : 1583 : chars[i++] = FREC;
490 : 1828 : if (how & CLEARED_NO)
491 : 1567 : chars[i++] = NREC;
492 : 1828 : if (how & CLEARED_VOIDED)
493 : 134 : chars[i++] = VREC;
494 : 1828 : chars[i] = '\0';
495 : :
496 : 1828 : pred_data = qof_query_char_predicate (QOF_CHAR_MATCH_ANY, chars);
497 : 1828 : if (!pred_data)
498 : 0 : return;
499 : :
500 : 1828 : param_list = qof_query_build_param_list (SPLIT_RECONCILE, nullptr);
501 : :
502 : 1828 : qof_query_add_term (q, param_list, pred_data, op);
503 : : }
504 : :
505 : : cleared_match_t
506 : 0 : xaccQueryGetClearedMatch(QofQuery * q)
507 : : {
508 : : QofQueryPredData *term_data;
509 : 0 : cleared_match_t cleared_match = CLEARED_ALL;
510 : : GSList *param_list;
511 : : GSList *terms, *tmp;
512 : 0 : char *chars = nullptr;
513 : :
514 : 0 : param_list = qof_query_build_param_list (SPLIT_RECONCILE, nullptr);
515 : 0 : terms = qof_query_get_term_type (q, param_list);
516 : 0 : g_slist_free (param_list);
517 : :
518 : 0 : for (tmp = terms; tmp; tmp = g_slist_next (tmp))
519 : : {
520 : 0 : term_data = static_cast<QofQueryPredData*>(tmp->data);
521 : :
522 : 0 : if (qof_query_char_predicate_get_char (term_data, &chars))
523 : : {
524 : 0 : cleared_match = CLEARED_NONE;
525 : :
526 : 0 : if (strstr (chars, "c"))
527 : 0 : cleared_match = (cleared_match_t)(cleared_match | CLEARED_CLEARED);
528 : 0 : if (strstr (chars, "y"))
529 : 0 : cleared_match = (cleared_match_t)(cleared_match | CLEARED_RECONCILED);
530 : 0 : if (strstr (chars, "f"))
531 : 0 : cleared_match = (cleared_match_t)(cleared_match | CLEARED_FROZEN);
532 : 0 : if (strstr (chars, "n"))
533 : 0 : cleared_match = (cleared_match_t)(cleared_match | CLEARED_NO);
534 : 0 : if (strstr (chars, "v"))
535 : 0 : cleared_match = (cleared_match_t)(cleared_match | CLEARED_VOIDED);
536 : : }
537 : : }
538 : 0 : g_slist_free (terms);
539 : :
540 : 0 : return cleared_match;
541 : : }
542 : :
543 : : void
544 : 762 : xaccQueryAddGUIDMatch(QofQuery * q, const GncGUID *guid,
545 : : QofIdType id_type, QofQueryOp op)
546 : : {
547 : 762 : GSList *param_list = nullptr;
548 : :
549 : 762 : if (!q || !guid || !id_type)
550 : 0 : return;
551 : :
552 : 762 : if (!g_strcmp0 (id_type, GNC_ID_SPLIT))
553 : 256 : param_list = qof_query_build_param_list (QOF_PARAM_GUID, nullptr);
554 : 506 : else if (!g_strcmp0 (id_type, GNC_ID_TRANS))
555 : 251 : param_list = qof_query_build_param_list (SPLIT_TRANS, QOF_PARAM_GUID, nullptr);
556 : 255 : else if (!g_strcmp0 (id_type, GNC_ID_ACCOUNT))
557 : 255 : param_list = qof_query_build_param_list (SPLIT_ACCOUNT, QOF_PARAM_GUID, nullptr);
558 : : else
559 : 0 : PERR ("Invalid match type: %s", id_type);
560 : :
561 : 762 : qof_query_add_guid_match (q, param_list, guid, op);
562 : : }
563 : :
564 : :
565 : : /********************************************************************
566 : : * xaccQueryAddClosingTransMatch
567 : : * Add a filter that matches book closing entries to an existing query.
568 : : ********************************************************************/
569 : :
570 : : void
571 : 208 : xaccQueryAddClosingTransMatch(QofQuery *q, gboolean value, QofQueryOp op)
572 : : {
573 : : GSList *param_list;
574 : :
575 : 208 : param_list = qof_query_build_param_list(SPLIT_TRANS, TRANS_IS_CLOSING, nullptr);
576 : 208 : qof_query_add_boolean_match(q, param_list, value, op);
577 : 208 : }
578 : :
579 : : /*******************************************************************
580 : : * xaccQueryGetEarliestDateFound
581 : : *******************************************************************/
582 : :
583 : : time64
584 : 0 : xaccQueryGetEarliestDateFound(QofQuery * q)
585 : : {
586 : : GList * spl;
587 : : Split * sp;
588 : : time64 earliest;
589 : :
590 : 0 : if (!q) return 0;
591 : 0 : spl = qof_query_last_run (q);
592 : 0 : if (!spl) return 0;
593 : :
594 : : /* Safe until 2038 on archs where time64 is 32bit */
595 : 0 : sp = GNC_SPLIT (spl->data);
596 : 0 : earliest = sp->parent->date_posted;
597 : 0 : for (; spl; spl = spl->next)
598 : : {
599 : 0 : sp = GNC_SPLIT (spl->data);
600 : 0 : if (sp->parent->date_posted < earliest)
601 : : {
602 : 0 : earliest = sp->parent->date_posted;
603 : : }
604 : : }
605 : 0 : return earliest;
606 : : }
607 : :
608 : : /*******************************************************************
609 : : * xaccQueryGetLatestDateFound
610 : : *******************************************************************/
611 : :
612 : : time64
613 : 0 : xaccQueryGetLatestDateFound(QofQuery * q)
614 : : {
615 : : Split * sp;
616 : : GList * spl;
617 : 0 : time64 latest = 0;
618 : :
619 : 0 : if (!q) return 0;
620 : 0 : spl = qof_query_last_run (q);
621 : 0 : if (!spl) return 0;
622 : :
623 : 0 : for (; spl; spl = spl->next)
624 : : {
625 : 0 : sp = GNC_SPLIT (spl->data);
626 : 0 : if (sp->parent->date_posted > latest)
627 : : {
628 : 0 : latest = sp->parent->date_posted;
629 : : }
630 : : }
631 : 0 : return latest;
632 : : }
633 : :
634 : : void
635 : 463 : xaccQueryAddDescriptionMatch(QofQuery *q, const char *m, gboolean c, gboolean r,
636 : : QofQueryCompare h, QofQueryOp o)
637 : : {
638 : 463 : xaccQueryAddStringMatch ((q), (m), (c), (r), (h), (o), SPLIT_TRANS,
639 : : TRANS_DESCRIPTION, nullptr);
640 : 463 : }
641 : :
642 : : void
643 : 0 : xaccQueryAddNotesMatch(QofQuery *q, const char *m, gboolean c, gboolean r,
644 : : QofQueryCompare h, QofQueryOp o)
645 : : {
646 : 0 : xaccQueryAddStringMatch ((q), (m), (c), (r), (h), (o), SPLIT_TRANS,
647 : : TRANS_NOTES, nullptr);
648 : 0 : }
649 : :
650 : : void
651 : 344 : xaccQueryAddNumberMatch(QofQuery *q, const char *m, gboolean c, gboolean r,
652 : : QofQueryCompare h, QofQueryOp o)
653 : : {
654 : 344 : xaccQueryAddStringMatch ((q), (m), (c), (r), (h), (o), SPLIT_TRANS,
655 : : TRANS_NUM, nullptr);
656 : 344 : }
657 : :
658 : : void
659 : 382 : xaccQueryAddActionMatch(QofQuery *q, const char *m, gboolean c, gboolean r,
660 : : QofQueryCompare h, QofQueryOp o)
661 : : {
662 : 382 : xaccQueryAddStringMatch ((q), (m), (c), (r), (h), (o), SPLIT_ACTION, nullptr);
663 : 382 : }
664 : :
665 : : void
666 : 374 : xaccQueryAddMemoMatch(QofQuery *q, const char *m, gboolean c, gboolean r,
667 : : QofQueryCompare h, QofQueryOp o)
668 : : {
669 : 374 : xaccQueryAddStringMatch ((q), (m), (c), (r), (h), (o), SPLIT_MEMO, nullptr);
670 : 374 : }
671 : :
672 : : void
673 : 356 : xaccQueryAddValueMatch(QofQuery *q, gnc_numeric amt, QofNumericMatch sgn,
674 : : QofQueryCompare how, QofQueryOp op)
675 : : {
676 : 356 : xaccQueryAddNumericMatch ((q), (amt), (sgn), (how), (op),
677 : : SPLIT_VALUE, nullptr);
678 : 356 : }
679 : :
680 : : void
681 : 358 : xaccQueryAddSharePriceMatch(QofQuery *q, gnc_numeric amt, QofQueryCompare how,
682 : : QofQueryOp op)
683 : : {
684 : 358 : xaccQueryAddNumericMatch ((q), (amt), QOF_NUMERIC_MATCH_ANY, (how), (op),
685 : : SPLIT_SHARE_PRICE, nullptr);
686 : 358 : }
687 : :
688 : : void
689 : 366 : xaccQueryAddSharesMatch(QofQuery *q, gnc_numeric amt, QofQueryCompare how,
690 : : QofQueryOp op)
691 : : {
692 : 366 : xaccQueryAddNumericMatch ((q), (amt), QOF_NUMERIC_MATCH_ANY, (how), (op),
693 : : SPLIT_AMOUNT, nullptr);
694 : 366 : }
695 : :
696 : : void
697 : 189 : xaccQueryAddBalanceMatch(QofQuery *q, QofQueryCompare bal, QofQueryOp op)
698 : : {
699 : 189 : xaccQueryAddNumericMatch(
700 : : (q), gnc_numeric_zero(), QOF_NUMERIC_MATCH_ANY,
701 : : ((bal) ? QOF_COMPARE_EQUAL : QOF_COMPARE_NEQ), (op),
702 : : SPLIT_TRANS, TRANS_IMBALANCE, nullptr);
703 : 189 : }
704 : :
705 : :
706 : : /* ======================== END OF FILE ======================= */
|