SQL QUERY API: As an alternative to building queries one predicate at a time, you can use the SQL query interface. This interface will accept a string containing an SQL query, parse it, convert it into the core representation, and execute it.
STRUCTURE OF A QUERY: A Query is a logical function of any number of QueryTerms. A QueryTerm consists of a C function pointer (the Predicate) and a PredicateData structure containing data passed to the predicate funtion. The PredicateData structure is a constant associated with the Term and is identical for every object that is tested.
The terms of the Query may represent any logical function and are stored in canonical form, i.e. the function is expressed as a logical sum of logical products. So if you have QueryTerms a, b, c, d, e and you have the logical function a(b+c) + !(c(d+e)), it gets stored as ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation of some functions but it's easy to store, easy to manipulate, and it doesn't require a complete algebra system to deal with.
The representation is of a GList of GLists of QueryTerms. The "backbone" GList q->terms represents the OR-chain, and every item on the backbone is a GList of QueryTerms representing an AND-chain corresponding to a single product-term in the canonical representation. QueryTerms are duplicated when necessary to fill out the canonical form, and the same predicate may be evaluated multiple times per split for complex queries. This is a place where we could probably optimize.
Evaluation of a Query (see qof_query_run()) is optimized as much as possible by short-circuited evaluation. The predicates in each AND-chain are sorted by predicate type, with Account queries sorted first to allow the evaluator to completely eliminate accounts from the search if there's no chance of them having splits that match. (XXX above no longer applies)
|
|
"Known" Object Parameters -- all objects must support these Definition at line 111 of file qofquery.h. |
|
|
"Known" Object Parameters -- some objects might support these Definition at line 115 of file qofquery.h. |
|
|
First/only term is same as 'and' Definition at line 105 of file qofquery.h. |
|
|
Default sort object type Definition at line 108 of file qofquery.h. |
|
|
A Query Definition at line 93 of file qofquery.h. |
|
|
PREDICATE DATA TYPES: All the predicate data types are rolled up into the union type PredicateData. The "type" field specifies which type the union is. Definition at line 47 of file qofquerycore.h. |
|
|
A CHAR type is for a RECNCell, Comparisons for QOF_TYPE_CHAR 'ANY' will match any charagter in the string. Match 'ANY' is a convenience/performance-enhanced predicate for the compound statement (value==char1) || (value==char2) || etc. Match 'NONE' is equivalent to (value != char1) && (value != char2) && etc. Definition at line 123 of file qofquerycore.h. 00123 { 00124 QOF_CHAR_MATCH_ANY = 1, 00125 QOF_CHAR_MATCH_NONE 00126 } QofCharMatch;
|
|
|
Comparisons for QOF_TYPE_DATE The QOF_DATE_MATCH_DAY comparison rounds the two time values to mid-day and then compares these rounded values. The QOF_DATE_MATCH_NORMAL comparison matches the time values, down to the second. Definition at line 77 of file qofquerycore.h. 00077 { 00078 QOF_DATE_MATCH_NORMAL = 1, 00079 QOF_DATE_MATCH_DAY 00080 } QofDateMatch;
|
|
|
Definition at line 101 of file qofquerycore.h. 00101 { 00104 QOF_GUID_MATCH_ANY = 1, 00105 QOF_GUID_MATCH_NONE, 00106 QOF_GUID_MATCH_NULL, 00109 QOF_GUID_MATCH_ALL, 00112 QOF_GUID_MATCH_LIST_ANY, 00113 } QofGuidMatch;
|
|
|
Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED XXX Should be deprecated, or at least wrapped up as a convenience function, this is based on the old bill gribble code, which assumed the amount was always positive, and then specified a funds-flow direction (credit, debit, or either). The point being that 'match credit' is equivalent to the compound predicate (amount >= 0) && (amount 'op' value) while the 'match debit' predicate is equivalent to (amount <= 0) && (abs(amount) 'op' value) Definition at line 94 of file qofquerycore.h. 00094 { 00095 QOF_NUMERIC_MATCH_DEBIT = 1, 00096 QOF_NUMERIC_MATCH_CREDIT, 00097 QOF_NUMERIC_MATCH_ANY 00098 } QofNumericMatch;
|
|
|
Standard Query comparitors, for how to compare objects in a predicate. Note that not all core types implement all comparitors Definition at line 52 of file qofquerycore.h. 00052 { 00053 QOF_COMPARE_LT = 1, 00054 QOF_COMPARE_LTE, 00055 QOF_COMPARE_EQUAL, 00056 QOF_COMPARE_GT, 00057 QOF_COMPARE_GTE, 00058 QOF_COMPARE_NEQ 00059 } QofQueryCompare;
|
|
|
Query Term Operators, for combining Query Terms Definition at line 96 of file qofquery.h. 00096 { 00097 QOF_QUERY_AND=1, 00098 QOF_QUERY_OR, 00099 QOF_QUERY_NAND, 00100 QOF_QUERY_NOR, 00101 QOF_QUERY_XOR 00102 } QofQueryOp;
|
|
|
List of known core query data-types... Each core query type defines it's set of optional "comparitor qualifiers". Definition at line 65 of file qofquerycore.h. 00065 { 00066 QOF_STRING_MATCH_NORMAL = 1, 00067 QOF_STRING_MATCH_CASEINSENSITIVE 00068 } QofStringMatch;
|
|
||||||||||||||||||||
|
Handy-dandy convenience routines, avoids having to create a separate predicate for boolean matches. We might want to create handy-dandy sugar routines for the other predicate types as well. Definition at line 1258 of file qofquery.c. 01260 { 01261 QofQueryPredData *pdata; 01262 if (!q || !param_list) return; 01263 01264 pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value); 01265 qof_query_add_term (q, param_list, pdata, op); 01266 }
|
|
||||||||||||||||||||||||
|
DOCUMENT ME !! Definition at line 1206 of file qofquery.c. 01209 { 01210 QofQueryPredData *pdata; 01211 01212 if (!q || !param_list) return; 01213 01214 if (!guid_list) 01215 g_return_if_fail (options == QOF_GUID_MATCH_NULL); 01216 01217 pdata = qof_query_guid_predicate (options, guid_list); 01218 qof_query_add_term (q, param_list, pdata, op); 01219 }
|
|
||||||||||||||||||||
|
DOCUMENT ME !! Definition at line 1221 of file qofquery.c. 01223 { 01224 GList *g = NULL; 01225 01226 if (!q || !param_list) return; 01227 01228 if (guid) 01229 g = g_list_prepend (g, (gpointer)guid); 01230 01231 qof_query_add_guid_list_match (q, param_list, g, 01232 g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op); 01233 01234 g_list_free (g); 01235 }
|
|
||||||||||||||||||||
|
This is the general function that adds a new Query Term to a query. It will find the 'obj_type' object of the search item and compare the 'param_list' parameter to the predicate data via the comparitor. The param_list is a recursive list of parameters. For example, you can say 'split->memo' by creating a list of one element, "SPLIT_MEMO". You can say 'split->account->name' by creating a list of two elements, "SPLIT_ACCOUNT" and "ACCOUNT_NAME". The list becomes the property of the Query. For example: acct_name_pred_data = make_string_pred_data(QOF_STRING_MATCH_CASEINSENSITIVE, account_name); param_list = make_list (SPLIT_ACCOUNT, ACCOUNT_NAME, NULL); qof_query_add_term (query, param_list, QOF_COMPARE_EQUAL, acct_name_pred_data, QOF_QUERY_AND); Please note that QofQuery does not, at this time, support joins. That is, one cannot specify a predicate that is a parameter list. Put another way, one cannot search for objects where obja->thingy == objb->stuff Definition at line 646 of file qofquery.c. 00648 { 00649 QofQueryTerm *qt; 00650 QofQuery *qr, *qs; 00651 00652 if (!q || !param_list || !pred_data) return; 00653 00654 qt = g_new0 (QofQueryTerm, 1); 00655 qt->param_list = param_list; 00656 qt->pdata = pred_data; 00657 qs = qof_query_create (); 00658 query_init (qs, qt); 00659 00660 if (qof_query_has_terms (q)) 00661 qr = qof_query_merge (q, qs, op); 00662 else 00663 qr = qof_query_merge (q, qs, QOF_QUERY_OR); 00664 00665 swap_terms (q, qr); 00666 qof_query_destroy (qs); 00667 qof_query_destroy (qr); 00668 }
|
|
|
Remove all query terms from query. query matches nothing after qof_query_clear(). Definition at line 821 of file qofquery.c. 00822 { 00823 QofQuery *q2 = qof_query_create (); 00824 swap_terms (query, q2); 00825 qof_query_destroy (q2); 00826 00827 g_list_free (query->books); 00828 query->books = NULL; 00829 g_list_free (query->results); 00830 query->results = NULL; 00831 query->changed = 1; 00832 }
|
|
|
Make a copy of the indicated query Definition at line 927 of file qofquery.c. 00928 { 00929 QofQuery *copy; 00930 GHashTable *ht; 00931 00932 if (!q) return NULL; 00933 copy = qof_query_create (); 00934 ht = copy->be_compiled; 00935 free_members (copy); 00936 00937 memcpy (copy, q, sizeof (QofQuery)); 00938 00939 copy->be_compiled = ht; 00940 copy->terms = copy_or_terms (q->terms); 00941 copy->books = g_list_copy (q->books); 00942 copy->results = g_list_copy (q->results); 00943 00944 copy_sort (&(copy->primary_sort), &(q->primary_sort)); 00945 copy_sort (&(copy->secondary_sort), &(q->secondary_sort)); 00946 copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort)); 00947 00948 copy->changed = 1; 00949 00950 return copy; 00951 }
|
|
|
Copy a predicate. Definition at line 1792 of file qofquerycore.c. 01793 { 01794 QueryPredicateCopyFunc copy; 01795 01796 g_return_val_if_fail (pdata, NULL); 01797 g_return_val_if_fail (pdata->type_name, NULL); 01798 01799 copy = qof_query_copy_predicate (pdata->type_name); 01800 return (copy (pdata)); 01801 }
|
|
|
Destroy a predicate. Definition at line 1780 of file qofquerycore.c. 01781 { 01782 QueryPredDataFree free_fcn; 01783 01784 g_return_if_fail (pdata); 01785 g_return_if_fail (pdata->type_name); 01786 01787 free_fcn = qof_query_predicate_free (pdata->type_name); 01788 free_fcn (pdata); 01789 }
|
|
||||||||||||||||
|
Return a printable string for a core data object. Caller needs to g_free() the returned string. Definition at line 1804 of file qofquerycore.c. 01806 { 01807 QueryToString toString; 01808 01809 g_return_val_if_fail (type, NULL); 01810 g_return_val_if_fail (object, NULL); 01811 g_return_val_if_fail (getter, NULL); 01812 01813 toString = g_hash_table_lookup (toStringTable, type); 01814 g_return_val_if_fail (toString, NULL); 01815 01816 return toString (object, getter); 01817 }
|
|
|
Create a new query. Before running the query, a 'search-for' type must be set otherwise nothing will be returned. The results of the query is a list of the indicated search-for type. Allocates and initializes a Query structure which must be freed by the user with qof_query_destroy(). A newly-allocated QofQuery object matches nothing (qof_query_run() will return NULL). Definition at line 834 of file qofquery.c. 00835 { 00836 QofQuery *qp = g_new0 (QofQuery, 1); 00837 qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal); 00838 query_init (qp, NULL); 00839 return qp; 00840 }
|
|
||||||||||||
|
Retrieve a predicate. Definition at line 379 of file qofquerycore.c. 00380 { 00381 query_date_t pdata = (query_date_t)pd; 00382 00383 if (pdata->pd.type_name != query_date_type) 00384 return FALSE; 00385 *date = pdata->date; 00386 return TRUE; 00387 }
|
|
|
Frees the resources associate with a Query object. Definition at line 918 of file qofquery.c. 00919 { 00920 if (!q) return; 00921 free_members (q); 00922 query_clear_compiles (q); 00923 g_hash_table_destroy (q->be_compiled); 00924 g_free (q); 00925 }
|
|
||||||||||||
|
Compare two queries for equality. Query terms are compared each to each. This is a simplistic implementation -- logical equivalences between different and/or trees are ignored. Definition at line 1382 of file qofquery.c. 01383 { 01384 GList *or1, *or2; 01385 01386 if (q1 == q2) return TRUE; 01387 if (!q1 || !q2) return FALSE; 01388 01389 if (g_list_length (q1->terms) != g_list_length (q2->terms)) return FALSE; 01390 if (q1->max_results != q2->max_results) return FALSE; 01391 01392 for (or1 = q1->terms, or2 = q2->terms; or1; 01393 or1 = or1->next, or2 = or2->next) 01394 { 01395 GList *and1, *and2; 01396 01397 and1 = or1->data; 01398 and2 = or2->data; 01399 01400 if (g_list_length (and1) != g_list_length (and2)) return FALSE; 01401 01402 for ( ; and1; and1 = and1->next, and2 = and2->next) 01403 if (!qof_query_term_equal (and1->data, and2->data)) 01404 return FALSE; 01405 } 01406 01407 if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort))) 01408 return FALSE; 01409 if (!qof_query_sort_equal (&(q1->secondary_sort), &(q2->secondary_sort))) 01410 return FALSE; 01411 if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort))) 01412 return FALSE; 01413 01414 return TRUE; 01415 }
|
|
|
Return the list of books we're using Definition at line 1252 of file qofquery.c. 01253 { 01254 if (!q) return NULL; 01255 return q->books; 01256 }
|
|
|
Return the type of data we're querying for Definition at line 1290 of file qofquery.c. 01291 { 01292 if (!q) return NULL; 01293 return q->search_for; 01294 }
|
|
||||||||||||
|
DOCUMENT ME !! Definition at line 879 of file qofquery.c. 00880 { 00881 GList *or; 00882 GList *and; 00883 00884 if (!q || !term_param) 00885 return FALSE; 00886 00887 for(or = q->terms; or; or = or->next) { 00888 for(and = or->data; and; and = and->next) { 00889 QofQueryTerm *qt = and->data; 00890 if (!param_list_cmp (term_param, qt->param_list)) 00891 return TRUE; 00892 } 00893 } 00894 00895 return FALSE; 00896 }
|
|
|
Return boolean FALSE if there are no terms in the query Can be used as a predicate to see if the query has been initialized (return value > 0) or is "blank" (return value == 0). Definition at line 863 of file qofquery.c. 00864 { 00865 if (!q) return 0; 00866 return g_list_length (q->terms); 00867 }
|
|
|
Subsystem initialization and shutdown. Call init() once to initalize the query subsytem; call shutdown() to free up any resources associated with the query subsystem. Typically called during application startup, shutdown. Definition at line 1271 of file qofquery.c. 01272 { 01273 ENTER (" "); 01274 qof_query_core_init (); 01275 qof_class_init (); 01276 }
|
|
|
Make a copy of the indicated query, inverting the sense of the search. In other words, if the original query search for all objects with a certain condition, the inverted query will search for all object with NOT that condition. The union of the results returned by the original and inverted queries equals the set of all searched objects. These to sets are disjoint (share no members in common). This will return a newly allocated QofQuery object, or NULL on error. Free it with qof_query_destroy() when no longer needed. Definition at line 959 of file qofquery.c. 00960 { 00961 QofQuery * retval; 00962 QofQuery * right, * left, * iright, * ileft; 00963 QofQueryTerm * qt; 00964 GList * aterms; 00965 GList * cur; 00966 GList * new_oterm; 00967 int num_or_terms; 00968 00969 if (!q) 00970 return NULL; 00971 00972 num_or_terms = g_list_length(q->terms); 00973 00974 switch(num_or_terms) 00975 { 00976 case 0: 00977 retval = qof_query_create(); 00978 retval->max_results = q->max_results; 00979 break; 00980 00981 /* This is the DeMorgan expansion for a single AND expression. */ 00982 /* !(abc) = !a + !b + !c */ 00983 case 1: 00984 retval = qof_query_create(); 00985 retval->max_results = q->max_results; 00986 retval->books = g_list_copy (q->books); 00987 retval->search_for = q->search_for; 00988 retval->changed = 1; 00989 00990 aterms = g_list_nth_data(q->terms, 0); 00991 new_oterm = NULL; 00992 for(cur=aterms; cur; cur=cur->next) { 00993 qt = copy_query_term(cur->data); 00994 qt->invert = !(qt->invert); 00995 new_oterm = g_list_append(NULL, qt); 00996 00997 /* g_list_append() can take forever, so let's do this for speed 00998 * in "large" queries. 00999 */ 01000 retval->terms = g_list_reverse(retval->terms); 01001 retval->terms = g_list_prepend(retval->terms, new_oterm); 01002 retval->terms = g_list_reverse(retval->terms); 01003 } 01004 break; 01005 01006 /* If there are multiple OR-terms, we just recurse by 01007 * breaking it down to !(a + b + c) = 01008 * !a * !(b + c) = !a * !b * !c. */ 01009 default: 01010 right = qof_query_create(); 01011 right->terms = copy_or_terms(g_list_nth(q->terms, 1)); 01012 01013 left = qof_query_create(); 01014 left->terms = g_list_append(NULL, 01015 copy_and_terms(g_list_nth_data(q->terms, 0))); 01016 01017 iright = qof_query_invert(right); 01018 ileft = qof_query_invert(left); 01019 01020 retval = qof_query_merge(iright, ileft, QOF_QUERY_AND); 01021 retval->books = g_list_copy (q->books); 01022 retval->max_results = q->max_results; 01023 retval->search_for = q->search_for; 01024 retval->changed = 1; 01025 01026 qof_query_destroy(iright); 01027 qof_query_destroy(ileft); 01028 qof_query_destroy(right); 01029 qof_query_destroy(left); 01030 break; 01031 } 01032 01033 return retval; 01034 }
|
|
||||||||||||||||
|
The qof_query_kvp_predicate() matches the object that has the value 'value' located at the path 'path'. In a certain sense, the 'path' is handled as if it were a paramter. Definition at line 1235 of file qofquerycore.c. 01237 { 01238 query_kvp_t pdata; 01239 GSList *node; 01240 01241 g_return_val_if_fail (path && value, NULL); 01242 01243 pdata = g_new0 (query_kvp_def, 1); 01244 pdata->pd.type_name = query_kvp_type; 01245 pdata->pd.how = how; 01246 pdata->value = kvp_value_copy (value); 01247 pdata->path = g_slist_copy (path); 01248 for (node = pdata->path; node; node = node->next) 01249 node->data = g_strdup (node->data); 01250 01251 return ((QofQueryPredData*)pdata); 01252 }
|
|
||||||||||||||||
|
Same predicate as above, except that 'path' is assumed to be a string containing slash-separated pathname. Definition at line 1255 of file qofquerycore.c. 01257 { 01258 QofQueryPredData *pd; 01259 GSList *spath = NULL; 01260 char *str, *p; 01261 01262 if (!path) return NULL; 01263 01264 str = g_strdup (path); 01265 p = str; 01266 if (0 == *p) return NULL; 01267 if ('/' == *p) p++; 01268 01269 while (p) 01270 { 01271 spath = g_slist_append (spath, p); 01272 p = strchr (p, '/'); 01273 if (p) { *p = 0; p++; } 01274 } 01275 01276 pd = qof_query_kvp_predicate (how, spath, value); 01277 g_free (str); 01278 return pd; 01279 }
|
|
|
Return the results of the last query, without causing the query to be re-run. Do NOT free the resulting list. This list is managed internally by QofQuery. Definition at line 813 of file qofquery.c. 00814 { 00815 if (!query) 00816 return NULL; 00817 00818 return query->results; 00819 }
|
|
||||||||||||||||
|
Combine two queries together using the Boolean set (logical) operator 'op'. For example, if the operator 'op' is set to QUERY_AND, then the set of results returned by the query will will be the Boolean set intersection of the results returned by q1 and q2. Similarly, QUERY_OR maps to set union, etc. Both queries must have compatible search-types. If both queries are set, they must search for the same object type. If only one is set, the resulting query will search for the set type. If neither query has the search-type set, the result will be unset as well. This will return a newly allocated QofQuery object, or NULL on error. Free it with qof_query_destroy() when no longer needed. Definition at line 1042 of file qofquery.c. 01043 { 01044 01045 QofQuery * retval = NULL; 01046 QofQuery * i1, * i2; 01047 QofQuery * t1, * t2; 01048 GList * i, * j; 01049 QofIdType search_for; 01050 01051 if(!q1) return q2; 01052 if(!q2) return q1; 01053 01054 if (q1->search_for && q2->search_for) 01055 g_return_val_if_fail (safe_strcmp (q1->search_for, q2->search_for) == 0, 01056 NULL); 01057 01058 search_for = (q1->search_for ? q1->search_for : q2->search_for); 01059 01060 /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty. 01061 * The goal of this tweak is to all the user to start with 01062 * an empty q1 and then append to it recursively 01063 * (and q1 (and q2 (and q3 (and q4 ....)))) 01064 * without bombing out because the append started with an 01065 * empty list. 01066 * We do essentially the same check in qof_query_add_term() 01067 * so that the first term added to an empty query doesn't screw up. 01068 */ 01069 if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1))) 01070 { 01071 op = QOF_QUERY_OR; 01072 } 01073 01074 switch(op) 01075 { 01076 case QOF_QUERY_OR: 01077 retval = qof_query_create(); 01078 retval->terms = 01079 g_list_concat(copy_or_terms(q1->terms), copy_or_terms(q2->terms)); 01080 retval->books = merge_books (q1->books, q2->books); 01081 retval->max_results = q1->max_results; 01082 retval->changed = 1; 01083 break; 01084 01085 case QOF_QUERY_AND: 01086 retval = qof_query_create(); 01087 retval->books = merge_books (q1->books, q2->books); 01088 retval->max_results = q1->max_results; 01089 retval->changed = 1; 01090 01091 /* g_list_append() can take forever, so let's build the list in 01092 * reverse and then reverse it at the end, to deal better with 01093 * "large" queries. 01094 */ 01095 for(i=q1->terms; i; i=i->next) 01096 { 01097 for(j=q2->terms; j; j=j->next) 01098 { 01099 retval->terms = 01100 g_list_prepend(retval->terms, 01101 g_list_concat 01102 (copy_and_terms(i->data), 01103 copy_and_terms(j->data))); 01104 } 01105 } 01106 retval->terms = g_list_reverse(retval->terms); 01107 break; 01108 01109 case QOF_QUERY_NAND: 01110 /* !(a*b) = (!a + !b) */ 01111 i1 = qof_query_invert(q1); 01112 i2 = qof_query_invert(q2); 01113 retval = qof_query_merge(i1, i2, QOF_QUERY_OR); 01114 qof_query_destroy(i1); 01115 qof_query_destroy(i2); 01116 break; 01117 01118 case QOF_QUERY_NOR: 01119 /* !(a+b) = (!a*!b) */ 01120 i1 = qof_query_invert(q1); 01121 i2 = qof_query_invert(q2); 01122 retval = qof_query_merge(i1, i2, QOF_QUERY_AND); 01123 qof_query_destroy(i1); 01124 qof_query_destroy(i2); 01125 break; 01126 01127 case QOF_QUERY_XOR: 01128 /* a xor b = (a * !b) + (!a * b) */ 01129 i1 = qof_query_invert(q1); 01130 i2 = qof_query_invert(q2); 01131 t1 = qof_query_merge(q1, i2, QOF_QUERY_AND); 01132 t2 = qof_query_merge(i1, q2, QOF_QUERY_AND); 01133 retval = qof_query_merge(t1, t2, QOF_QUERY_OR); 01134 01135 qof_query_destroy(i1); 01136 qof_query_destroy(i2); 01137 qof_query_destroy(t1); 01138 qof_query_destroy(t2); 01139 break; 01140 } 01141 01142 retval->search_for = search_for; 01143 return retval; 01144 }
|
|
||||||||||||||||
|
Like qof_query_merge, but this will merge a copy of q2 into q1. q2 remains unchanged. Definition at line 1147 of file qofquery.c. 01148 { 01149 QofQuery *tmp_q; 01150 01151 if (!q1 || !q2) 01152 return; 01153 01154 tmp_q = qof_query_merge (q1, q2, op); 01155 swap_terms (q1, tmp_q); 01156 qof_query_destroy (tmp_q); 01157 }
|
|
|
Return the number of terms in the canonical form of the query. Definition at line 869 of file qofquery.c. 00870 { 00871 GList *o; 00872 int n = 0; 00873 if (!q) return 0; 00874 for (o = q->terms; o; o=o->next) 00875 n += g_list_length(o->data); 00876 return n; 00877 }
|
|
|
Print the Query in human-readable format. Useful for debugging and development. Definition at line 1446 of file qofquery.c. 01447 { 01448 GList *output; 01449 GString *str; 01450 QofQuerySort *s[3]; 01451 gint maxResults = 0, numSorts = 3; 01452 01453 ENTER (" "); 01454 01455 if (!query) { 01456 LEAVE("query is (null)"); 01457 return; 01458 } 01459 01460 output = NULL; 01461 str = NULL; 01462 maxResults = qof_query_get_max_results (query); 01463 01464 output = qof_query_printSearchFor (query, output); 01465 output = qof_query_printTerms (query, output); 01466 01467 qof_query_get_sorts (query, &s[0], &s[1], &s[2]); 01468 01469 if (s[0]) 01470 { 01471 output = qof_query_printSorts (s, numSorts, output); 01472 } 01473 01474 str = g_string_new (" "); 01475 g_string_sprintf (str, "Maximum number of results: %d", maxResults); 01476 output = g_list_append (output, str); 01477 01478 qof_query_printOutput (output); 01479 LEAVE (" "); 01480 }
|
|
||||||||||||
|
Remove query terms of a particular type from q. The "type" of a term is determined by the type of data that gets passed to the predicate function. XXX ??? Huh? remove anything of that predicate type, or just the particular predicate ? Definition at line 670 of file qofquery.c. 00671 { 00672 QofQueryTerm *qt; 00673 GList *or, *and; 00674 00675 if (!q || !param_list) return; 00676 00677 for (or = q->terms; or; or = or->next) { 00678 for (and = or->data; and; and = and->next) { 00679 qt = and->data; 00680 if (!param_list_cmp (qt->param_list, param_list)) { 00681 if (g_list_length (or->data) == 1) { 00682 q->terms = g_list_remove_link (q->terms, or); 00683 g_list_free_1 (or); 00684 or = q->terms; 00685 break; 00686 } else { 00687 or->data = g_list_remove_link (or->data, and); 00688 g_list_free_1 (and); 00689 and = or->data; 00690 if (!and) break; 00691 } 00692 q->changed = 1; 00693 free_query_term (qt); 00694 } 00695 } 00696 if (!or) break; 00697 } 00698 }
|
|
|
Perform the query, return the results. The returned list is a list of the 'search-for' type that was previously set with the qof_query_search_for() or the qof_query_create_for() routines. The returned list will have been sorted using the indicated sort order, and trimed to the max_results length. Do NOT free the resulting list. This list is managed internally by QofQuery. Definition at line 700 of file qofquery.c. 00701 { 00702 GList *matching_objects = NULL; 00703 GList *node; 00704 int object_count = 0; 00705 00706 if (!q) return NULL; 00707 g_return_val_if_fail (q->search_for, NULL); 00708 g_return_val_if_fail (q->books, NULL); 00709 ENTER (" q=%p", q); 00710 00711 /* XXX: Prioritize the query terms? */ 00712 00713 /* prepare the Query for processing */ 00714 if (q->changed) 00715 { 00716 query_clear_compiles (q); 00717 compile_terms (q); 00718 } 00719 00720 /* Maybe log this sucker */ 00721 if (gnc_should_log (log_module, GNC_LOG_DETAIL)) qof_query_print (q); 00722 00723 /* Now run the query over all the objects and save the results */ 00724 { 00725 QofQueryCB qcb; 00726 00727 memset (&qcb, 0, sizeof (qcb)); 00728 qcb.query = q; 00729 00730 /* For each book */ 00731 for (node=q->books; node; node=node->next) 00732 { 00733 QofBook *book = node->data; 00734 QofBackend *be = book->backend; 00735 00736 /* run the query in the backend */ 00737 if (be) 00738 { 00739 gpointer compiled_query = g_hash_table_lookup (q->be_compiled, book); 00740 00741 if (compiled_query && be->run_query) 00742 { 00743 (be->run_query) (be, compiled_query); 00744 } 00745 } 00746 00747 /* And then iterate over all the objects */ 00748 qof_object_foreach (q->search_for, book, (QofEntityForeachCB) check_item_cb, &qcb); 00749 } 00750 00751 matching_objects = qcb.list; 00752 object_count = qcb.count; 00753 } 00754 PINFO ("matching objects=%p count=%d", matching_objects, object_count); 00755 00756 /* There is no absolute need to reverse this list, since it's being 00757 * sorted below. However, in the common case, we will be searching 00758 * in a confined location where the objects are already in order, 00759 * thus reversing will put us in the correct order we want and make 00760 * the sorting go much faster. 00761 */ 00762 matching_objects = g_list_reverse(matching_objects); 00763 00764 /* Now sort the matching objects based on the search criteria 00765 * sortQuery is an unforgivable use of static global data... 00766 * I just can't figure out how else to do this sanely. 00767 */ 00768 if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp || 00769 (q->primary_sort.use_default && q->defaultSort)) 00770 { 00771 sortQuery = q; 00772 matching_objects = g_list_sort(matching_objects, sort_func); 00773 sortQuery = NULL; 00774 } 00775 00776 /* Crop the list to limit the number of splits. */ 00777 if((object_count > q->max_results) && (q->max_results > -1)) 00778 { 00779 if(q->max_results > 0) 00780 { 00781 GList *mptr; 00782 00783 /* mptr is set to the first node of what will be the new list */ 00784 mptr = g_list_nth(matching_objects, object_count - q->max_results); 00785 /* mptr should not be NULL, but let's be safe */ 00786 if (mptr != NULL) 00787 { 00788 if (mptr->prev != NULL) mptr->prev->next = NULL; 00789 mptr->prev = NULL; 00790 } 00791 g_list_free(matching_objects); 00792 matching_objects = mptr; 00793 } 00794 else 00795 { 00796 /* q->max_results == 0 */ 00797 g_list_free(matching_objects); 00798 matching_objects = NULL; 00799 } 00800 object_count = q->max_results; 00801 } 00802 00803 q->changed = 0; 00804 00805 g_list_free(q->results); 00806 q->results = matching_objects; 00807 00808 LEAVE (" q=%p", q); 00809 return matching_objects; 00810 }
|
|
||||||||||||
|
Set the object type to be searched for. The results of performuing the query will be a list of this obj_type. Definition at line 842 of file qofquery.c. 00843 { 00844 if (!q || !obj_type) 00845 return; 00846 00847 if (safe_strcmp (q->search_for, obj_type)) { 00848 q->search_for = (QofIdType) obj_type; 00849 q->changed = 1; 00850 } 00851 }
|
|
||||||||||||
|
Set the book to be searched. Books contain/identify collections of objects; the search will be performed over those books specified with this function. If no books are set, no results will be returned (since there is nothing to search over). You can search multiple books. To specify multiple books, call this function multiple times with different arguments. XXX needed qof_query_clear_books() to reset the list ... Definition at line 1237 of file qofquery.c. 01238 { 01239 GSList *slist = NULL; 01240 if (!q || !book) return; 01241 01242 /* Make sure this book is only in the list once */ 01243 if (g_list_index (q->books, book) == -1) 01244 q->books = g_list_prepend (q->books, book); 01245 01246 g_slist_prepend (slist, QOF_PARAM_GUID); 01247 g_slist_prepend (slist, QOF_PARAM_BOOK); 01248 qof_query_add_guid_match (q, slist, 01249 qof_book_get_guid(book), QOF_QUERY_AND); 01250 }
|
|
||||||||||||
|
Set the maximum number of results that should be returned. If 'max-results' is set to -1, then all of the results are returned. If there are more results than 'max-results', then the result list is trimmed. Note that there is an important interplay between 'max-results' and the sort order: only the last bit of results are returned. For example, if the sort order is set to be increasing date order, then only the objects with the most recent dates will be returned. Definition at line 1200 of file qofquery.c. 01201 { 01202 if (!q) return; 01203 q->max_results = n; 01204 }
|
|
||||||||||||||||||||
|
When a query is run, the results are sorted before being returned. This routine can be used to control the direction of the ordering. A value of TRUE indicates the sort will be in increasing order, a value of FALSE will order results in decreasing order. Note that if there are more results than the 'max-results' value, then only the *last* max-results will be returned. For example, if the sort is set to be increasing date order, then only the objects with the most recent dates will be returned. Definition at line 1191 of file qofquery.c. 01193 { 01194 if (!q) return; 01195 q->primary_sort.increasing = prim_inc; 01196 q->secondary_sort.increasing = sec_inc; 01197 q->tertiary_sort.increasing = tert_inc; 01198 }
|
|
||||||||||||||||||||
|
When a query is run, the results are sorted before being returned. This routine can be used to set the paramters on which the sort will be performed. Two objects in the result list will be compared using the 'primary_sort_params', and sorted based on that order. If the comparison shows that they are equal, then the 'secondary_sort_params' will be used. If still equal, then the tertiary params will be compared. Any or all of these parameter lists may be NULL. Any of these parameter lists may be set to QUERY_DEFAULT_SORT. Note that if there are more results than the 'max-results' value, then only the *last* max-results will be returned. For example, if the sort is set to be increasing date order, then only the objects with the most recent dates will be returned. The input lists become the property of QofQuery and are managed by it. They will be freed when the query is destroyed (or when new lists are set). Definition at line 1160 of file qofquery.c. 01162 { 01163 if (!q) return; 01164 if (q->primary_sort.param_list) 01165 g_slist_free (q->primary_sort.param_list); 01166 q->primary_sort.param_list = params1; 01167 q->primary_sort.options = 0; 01168 01169 if (q->secondary_sort.param_list) 01170 g_slist_free (q->secondary_sort.param_list); 01171 q->secondary_sort.param_list = params2; 01172 q->secondary_sort.options = 0; 01173 01174 if (q->tertiary_sort.param_list) 01175 g_slist_free (q->tertiary_sort.param_list); 01176 q->tertiary_sort.param_list = params3; 01177 q->tertiary_sort.options = 0; 01178 01179 q->changed = 1; 01180 }
|
1.4.5