1 /********************************************************************\
2  * qofquery.h -- find objects that match a certain expression.      *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20  *                                                                  *
21 \********************************************************************/
22 
23 /** @addtogroup Query
24 
25 BASIC QUERY API:
26 With this API you can create arbitrary logical
27 queries to find sets of arbitrary object.  To make simple
28 queries (1 term, such as a search for a parameter with one value),
29 create the appropriate
30 QueryTerm structure and stick it in a Query object using
31 xaccInitQuery. The QueryTerm should be malloc'd but the Query object
32 will handle freeing it.  To make compound queries, make multiple
33 simple queries and combine them using qof_query_merge() and the logical
34 operations of your choice.
35 
36 SQL QUERY API:
37 As an alternative to building queries one predicate at a time,
38 you can use the SQL query interface.  This interface will accept
39 a string containing an SQL query, parse it, convert it into the
40 core representation, and execute it.
41 
42 STRUCTURE OF A QUERY: A Query is a logical function of any number of
43 QueryTerms.  A QueryTerm consists of a C function pointer (the
44 Predicate) and a PredicateData structure containing data passed to the
45 predicate function.  The PredicateData structure is a constant
46 associated with the Term and is identical for every object that is
47 tested.
48 
49 The terms of the Query may represent any logical function and are
50 stored in canonical form, i.e. the function is expressed as a logical
51 sum of logical products.  So if you have QueryTerms a, b, c, d, e and
52 you have the logical function a(b+c) + !(c(d+e)), it gets stored as
53 ab + ac + !c + !c!e +!d!c + !d!e.  This may not be optimal for evaluation
54 of some functions but it's easy to store, easy to manipulate, and it
55 doesn't require a complete algebra system to deal with.
56 
57 The representation is of a GList of GLists of QueryTerms.  The
58 "backbone" GList q->terms represents the OR-chain, and every item on
59 the backbone is a GList of QueryTerms representing an AND-chain
60 corresponding to a single product-term in the canonical
61 representation.  QueryTerms are duplicated when necessary to fill out
62 the canonical form, and the same predicate may be evaluated multiple
63 times per split for complex queries.  This is a place where we could
64 probably optimize.
65 
66  @{ */
67 /** @file qofquery.h
68     @brief find objects that match a certain expression.
69     @author Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>
70     @author Copyright (C) 2003 Linas Vepstas <linas@linas.org>
71 
72 */
73 
74 #ifndef QOF_QUERYNEW_H
75 #define QOF_QUERYNEW_H
76 
77 #include "guid.h"
78 #include "qofbook.h"
79 #include "qofquerycore.h"
80 #include "qofchoice.h"
81 
82 #ifdef __cplusplus
83 extern "C"
84 {
85 #endif
86 
87 #define QOF_MOD_QUERY "qof.query"
88 
89 /** A Query */
90 typedef struct _QofQuery QofQuery;
91 
92 /** Query Term Operators, for combining Query Terms */
93 typedef enum
94 {
95     QOF_QUERY_AND = 1,
96     QOF_QUERY_OR,
97     QOF_QUERY_NAND,
98     QOF_QUERY_NOR,
99     QOF_QUERY_XOR
100 } QofQueryOp;
101 
102 /** First/only term is same as 'and' */
103 #define QOF_QUERY_FIRST_TERM QOF_QUERY_AND
104 
105 /** Default sort object type */
106 #define QUERY_DEFAULT_SORT      "QofQueryDefaultSort"
107 
108 /** "Known" Object Parameters -- all objects must support these */
109 #define QOF_PARAM_BOOK    "book"
110 #define QOF_PARAM_GUID    "guid"
111 
112 /** "Known" Object Parameters -- some objects might support these */
113 #define QOF_PARAM_KVP     "kvp"
114 #define QOF_PARAM_ACTIVE  "active"
115 #define QOF_PARAM_VERSION "version"
116 
117 /* --------------------------------------------------------- */
118 /** \name Query Subsystem Initialization and Shudown  */
119 // @{
120 /** Subsystem initialization and shutdown. Call init() once
121  *  to initialize the query subsystem; call shutdown() to free
122  *  up any resources associated with the query subsystem.
123  *  Typically called during application startup, shutdown.
124  */
125 
126 void qof_query_init (void);
127 void qof_query_shutdown (void);
128 // @}
129 
130 /* --------------------------------------------------------- */
131 /** \name Low-Level API Functions */
132 // @{
133 
134 QofQueryParamList * qof_query_build_param_list (char const *param, ...);
135 
136 /** Create a new query.
137  *  Before running the query, a 'search-for' type must be set
138  *  otherwise nothing will be returned.  The results of the query
139  *  is a list of the indicated search-for type.
140  *
141  *  Allocates and initializes a Query structure which must be
142  *  freed by the user with qof_query_destroy().  A newly-allocated
143  *  QofQuery object matches nothing (qof_query_run() will return NULL).
144  */
145 QofQuery * qof_query_create (void);
146 QofQuery * qof_query_create_for (QofIdTypeConst obj_type);
147 
148 /** Frees the resources associate with a Query object.  */
149 void qof_query_destroy (QofQuery *q);
150 
151 /** Set the object type to be searched for.  The results of
152  *  performing the query will be a list of this obj_type.
153  */
154 void qof_query_search_for (QofQuery *query, QofIdTypeConst obj_type);
155 
156 /** Set the book to be searched.  Books contain/identify collections
157  *  of objects; the search will be performed over those books
158  *  specified with this function.  If no books are set, no results
159  *  will be returned (since there is nothing to search over).
160  *
161  *  You can search multiple books.  To specify multiple books, call
162  *  this function multiple times with different arguments.
163  * XXX needed qof_query_clear_books() to reset the list ...
164  */
165 void qof_query_set_book (QofQuery *q, QofBook *book);
166 
167 
168 /** This is the general function that adds a new Query Term to a query.
169  * It will find the 'obj_type' object of the search item and compare
170  * the 'param_list' parameter to the predicate data via the comparator.
171  *
172  * The param_list is a recursive list of parameters.  For example, you
173  * can say 'split->memo' by creating a list of one element, "SPLIT_MEMO".
174  * You can say 'split->account->name' by creating a list of two elements,
175  * "SPLIT_ACCOUNT" and "ACCOUNT_NAME".  The list becomes the property of
176  * the Query.
177  *
178  * For example:
179  *
180  * acct_name_pred_data = make_string_pred_data(QOF_STRING_MATCH_CASEINSENSITIVE,
181  *                                          account_name);
182  * param_list = make_list (SPLIT_ACCOUNT, ACCOUNT_NAME, NULL);
183  * qof_query_add_term (query, param_list, QOF_COMPARE_EQUAL,
184  *                    acct_name_pred_data, QOF_QUERY_AND);
185  *
186  * Please note that QofQuery does not, at this time, support joins.
187  * That is, one cannot specify a predicate that is a parameter list.
188  * Put another way, one cannot search for objects where
189  *   obja->thingy == objb->stuff
190  */
191 
192 void qof_query_add_term (QofQuery *query, QofQueryParamList *param_list,
193                          QofQueryPredData *pred_data, QofQueryOp op);
194 
195 /** DOCUMENT ME !! */
196 void qof_query_add_guid_match (QofQuery *q, QofQueryParamList *param_list,
197                                const GncGUID *guid, QofQueryOp op);
198 /** DOCUMENT ME !! */
199 void qof_query_add_guid_list_match (QofQuery *q, QofQueryParamList *param_list,
200                                     GList *guid_list, QofGuidMatch options,
201                                     QofQueryOp op);
202 
203 /** Handy-dandy convenience routines, avoids having to create
204  * a separate predicate for boolean matches.  We might want to
205  * create handy-dandy sugar routines for the other predicate types
206  * as well. */
207 void qof_query_add_boolean_match (QofQuery *q,
208                                   QofQueryParamList *param_list,
209                                   gboolean value,
210                                   QofQueryOp op);
211 
212 /** Perform the query, return the results.
213  *  The returned list is a list of the 'search-for' type that was
214  *  previously set with the qof_query_search_for() or the
215  *  qof_query_create_for() routines.  The returned list will have
216  *  been sorted using the indicated sort order, and trimmed to the
217  *  max_results length.
218  *
219  *  Do NOT free the resulting list.  This list is managed internally
220  *  by QofQuery.
221  */
222 GList * qof_query_run (QofQuery *query);
223 
224 /** Return the results of the last query, without causing the query to
225  *  be re-run.  Do NOT free the resulting list.  This list is managed
226  *  internally by QofQuery.
227  */
228 GList * qof_query_last_run (QofQuery *query);
229 
230 /** Perform a subquery, return the results.
231  *  Instead of running over a book, the subquery runs over the results
232  *  of the primary query.
233  *
234  *  Do NOT free the resulting list.  This list is managed internally
235  *  by QofQuery.
236  */
237 GList * qof_query_run_subquery (QofQuery *subquery,
238                                 const QofQuery* primary_query);
239 
240 /** Remove all query terms from query.  query matches nothing
241  *  after qof_query_clear().
242  */
243 void qof_query_clear (QofQuery *query);
244 
245 /** Remove query terms of a particular type from q.  The "type" of a term
246  *  is determined by the type of data that gets passed to the predicate
247  *  function.
248  * XXX ??? Huh? remove anything of that predicate type, or just
249  * the particular predicate ?
250  */
251 void qof_query_purge_terms (QofQuery *q, QofQueryParamList *param_list);
252 
253 /** Return boolean FALSE if there are no terms in the query
254  *  Can be used as a predicate to see if the query has been
255  *  initialized (return value > 0) or is "blank" (return value == 0).
256  */
257 int qof_query_has_terms (QofQuery *q);
258 
259 /** Return the number of terms in the canonical form of the query.
260  */
261 int qof_query_num_terms (QofQuery *q);
262 
263 /** DOCUMENT ME !! */
264 gboolean qof_query_has_term_type (QofQuery *q, QofQueryParamList *term_param);
265 GSList * qof_query_get_term_type (QofQuery *q, QofQueryParamList *term_param);
266 
267 /** Make a copy of the indicated query */
268 QofQuery * qof_query_copy (QofQuery *q);
269 
270 /** Make a copy of the indicated query, inverting the sense
271  *  of the search.  In other words, if the original query search
272  *  for all objects with a certain condition, the inverted query
273  *  will search for all object with NOT that condition.  The union
274  *  of the results returned by the original and inverted queries
275  *  equals the set of all searched objects. These to sets are
276  *  disjoint (share no members in common).
277  *
278  *  This will return a newly allocated QofQuery object, or NULL
279  *  on error. Free it with qof_query_destroy() when no longer needed.
280  */
281 QofQuery * qof_query_invert(QofQuery *q);
282 
283 /** Combine two queries together using the Boolean set (logical)
284  *  operator 'op'.  For example, if the operator 'op' is set to
285  *  QUERY_AND, then the set of results returned by the query will
286  *  will be the Boolean set intersection of the results returned
287  *  by q1 and q2.  Similarly,  QUERY_OR maps to set union, etc.
288  *
289  *  Both queries must have compatible
290  *  search-types.  If both queries are set, they must search for the
291  *  same object type.  If only one is set, the resulting query will
292  *  search for the set type.  If neither query has the search-type set,
293  *  the result will be unset as well.
294  *
295  *  This will return a newly allocated QofQuery object, or NULL on
296  *  error. Free it with qof_query_destroy() when no longer needed.
297  *  Note that if either input query is NULL then the returned query is
298  *  NOT newly allocated -- it will return the non-NULL query.  You
299  *  only need to call this function when both q1 and q2 are non-NULL.
300  */
301 QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op);
302 
303 /** Like qof_query_merge, but this will merge a copy of q2 into q1.
304  *   q2 remains unchanged.
305  */
306 void qof_query_merge_in_place(QofQuery *q1, QofQuery *q2, QofQueryOp op);
307 
308 /**
309  * When a query is run, the results are sorted before being returned.
310  * This routine can be used to set the parameters on which the sort will
311  * be performed.  Two objects in the result list will be compared using
312  * the 'primary_sort_params', and sorted based on that order.  If the
313  * comparison shows that they are equal, then the
314  * 'secondary_sort_params' will be used.  If still equal, then the
315  * tertiary parameters will be compared.  Any or all of these parameter
316  * lists may be NULL.  Any of these parameter lists may be set to
317  * QUERY_DEFAULT_SORT.
318  *
319  * Note that if there are more results than the 'max-results' value,
320  * then only the *last* max-results will be returned.  For example,
321  * if the sort is set to be increasing date order, then only the
322  * objects with the most recent dates will be returned.
323  *
324  * The input lists become the property of QofQuery and are managed
325  * by it.   They will be freed when the query is destroyed (or when
326  * new lists are set).
327  */
328 void qof_query_set_sort_order (QofQuery *q,
329                                QofQueryParamList *primary_sort_params,
330                                QofQueryParamList *secondary_sort_params,
331                                QofQueryParamList *tertiary_sort_params);
332 
333 void qof_query_set_sort_options (QofQuery *q, gint prim_op, gint sec_op,
334                                  gint tert_op);
335 
336 /**
337  * When a query is run, the results are sorted before being returned.
338  * This routine can be used to control the direction of the ordering.
339  * A value of TRUE indicates the sort will be in increasing order,
340  * a value of FALSE will order results in decreasing order.
341  *
342  * Note that if there are more results than the 'max-results' value,
343  * then only the *last* max-results will be returned.  For example,
344  * if the sort is set to be increasing date order, then only the
345  * objects with the most recent dates will be returned.
346  */
347 void qof_query_set_sort_increasing (QofQuery *q, gboolean prim_inc,
348                                     gboolean sec_inc, gboolean tert_inc);
349 
350 
351 /**
352  * Set the maximum number of results that should be returned.
353  * If 'max-results' is set to -1, then all of the results are
354  * returned.  If there are more results than 'max-results',
355  * then the result list is trimmed.  Note that there is an
356  * important interplay between 'max-results' and the sort order:
357  * only the last bit of results are returned.  For example,
358  * if the sort order is set to be increasing date order, then
359  * only the objects with the most recent dates will be returned.
360  */
361 void qof_query_set_max_results (QofQuery *q, int n);
362 
363 /** Compare two queries for equality.
364  * Query terms are compared each to each.
365  * This is a simplistic
366  * implementation -- logical equivalences between different
367  * and/or trees are ignored.
368  */
369 gboolean qof_query_equal (const QofQuery *q1, const QofQuery *q2);
370 
371 /** Log the Query
372  *
373  * \deprecated Do not call directly, use the standard log
374  * module code: ::qof_log_set_level(QOF_MOD_QUERY, QOF_LOG_DEBUG);
375  */
376 void qof_query_print (QofQuery *query);
377 
378 /** Return the type of data we're querying for */
379 /*@ dependent @*/
380 QofIdType qof_query_get_search_for (const QofQuery *q);
381 
382 /** Return the list of books we're using */
383 GList * qof_query_get_books (QofQuery *q);
384 
385 // @}
386 /* @} */
387 #ifdef __cplusplus
388 }
389 #endif
390 
391 #endif /* QOF_QUERYNEW_H */
392