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