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 109 of file qofquery.h. |
|
|
"Known" Object Parameters -- some objects might support these Definition at line 113 of file qofquery.h. |
|
|
Default sort object type Definition at line 106 of file qofquery.h. |
|
|
A Query Definition at line 91 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 125 of file qofquerycore.h. 00125 { 00126 QOF_CHAR_MATCH_ANY = 1, 00127 QOF_CHAR_MATCH_NONE 00128 } 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 79 of file qofquerycore.h. 00079 { 00080 QOF_DATE_MATCH_NORMAL = 1, 00081 QOF_DATE_MATCH_DAY 00082 } QofDateMatch;
|
|
|
Definition at line 103 of file qofquerycore.h. 00103 { 00106 QOF_GUID_MATCH_ANY = 1, 00107 QOF_GUID_MATCH_NONE, 00108 QOF_GUID_MATCH_NULL, 00111 QOF_GUID_MATCH_ALL, 00114 QOF_GUID_MATCH_LIST_ANY, 00115 } QofGuidMatch;
|
|
|
Comparisons for QOF_TYPE_NUMERIC, QOF_TYPE_DEBCRED XXX Should be deprecated, or at least wrapped up as a convnience 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 96 of file qofquerycore.h. 00096 { 00097 QOF_NUMERIC_MATCH_DEBIT = 1, 00098 QOF_NUMERIC_MATCH_CREDIT, 00099 QOF_NUMERIC_MATCH_ANY 00100 } 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 94 of file qofquery.h. 00094 { 00095 QOF_QUERY_AND=1, 00096 QOF_QUERY_OR, 00097 QOF_QUERY_NAND, 00098 QOF_QUERY_NOR, 00099 QOF_QUERY_XOR 00100 } 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 1257 of file qofquery.c. 01259 { 01260 QofQueryPredData *pdata; 01261 if (!q || !param_list) return; 01262 01263 pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value); 01264 qof_query_add_term (q, param_list, pdata, op); 01265 }
|
|
||||||||||||||||||||||||
|
DOCUMENT ME !! Definition at line 1205 of file qofquery.c. 01208 { 01209 QofQueryPredData *pdata; 01210 01211 if (!q || !param_list) return; 01212 01213 if (!guid_list) 01214 g_return_if_fail (options == QOF_GUID_MATCH_NULL); 01215 01216 pdata = qof_query_guid_predicate (options, guid_list); 01217 qof_query_add_term (q, param_list, pdata, op); 01218 }
|
|
||||||||||||||||||||
|
DOCUMENT ME !! Definition at line 1220 of file qofquery.c. 01222 { 01223 GList *g = NULL; 01224 01225 if (!q || !param_list) return; 01226 01227 if (guid) 01228 g = g_list_prepend (g, (gpointer)guid); 01229 01230 qof_query_add_guid_list_match (q, param_list, g, 01231 g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op); 01232 01233 g_list_free (g); 01234 }
|
|
||||||||||||||||||||
|
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 645 of file qofquery.c. 00647 { 00648 QofQueryTerm *qt; 00649 QofQuery *qr, *qs; 00650 00651 if (!q || !param_list || !pred_data) return; 00652 00653 qt = g_new0 (QofQueryTerm, 1); 00654 qt->param_list = param_list; 00655 qt->pdata = pred_data; 00656 qs = qof_query_create (); 00657 query_init (qs, qt); 00658 00659 if (qof_query_has_terms (q)) 00660 qr = qof_query_merge (q, qs, op); 00661 else 00662 qr = qof_query_merge (q, qs, QOF_QUERY_OR); 00663 00664 swap_terms (q, qr); 00665 qof_query_destroy (qs); 00666 qof_query_destroy (qr); 00667 }
|
|
|
Remove all query terms from query. query matches nothing after qof_query_clear(). Definition at line 820 of file qofquery.c. 00821 { 00822 QofQuery *q2 = qof_query_create (); 00823 swap_terms (query, q2); 00824 qof_query_destroy (q2); 00825 00826 g_list_free (query->books); 00827 query->books = NULL; 00828 g_list_free (query->results); 00829 query->results = NULL; 00830 query->changed = 1; 00831 }
|
|
|
Make a copy of the indicated query Definition at line 926 of file qofquery.c. 00927 { 00928 QofQuery *copy; 00929 GHashTable *ht; 00930 00931 if (!q) return NULL; 00932 copy = qof_query_create (); 00933 ht = copy->be_compiled; 00934 free_members (copy); 00935 00936 memcpy (copy, q, sizeof (QofQuery)); 00937 00938 copy->be_compiled = ht; 00939 copy->terms = copy_or_terms (q->terms); 00940 copy->books = g_list_copy (q->books); 00941 copy->results = g_list_copy (q->results); 00942 00943 copy_sort (&(copy->primary_sort), &(q->primary_sort)); 00944 copy_sort (&(copy->secondary_sort), &(q->secondary_sort)); 00945 copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort)); 00946 00947 copy->changed = 1; 00948 00949 return copy; 00950 }
|
|
|
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 833 of file qofquery.c. 00834 { 00835 QofQuery *qp = g_new0 (QofQuery, 1); 00836 qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal); 00837 query_init (qp, NULL); 00838 return qp; 00839 }
|
|
||||||||||||
|
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 917 of file qofquery.c. 00918 { 00919 if (!q) return; 00920 free_members (q); 00921 query_clear_compiles (q); 00922 g_hash_table_destroy (q->be_compiled); 00923 g_free (q); 00924 }
|
|
||||||||||||
|
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 1381 of file qofquery.c. 01382 { 01383 GList *or1, *or2; 01384 01385 if (q1 == q2) return TRUE; 01386 if (!q1 || !q2) return FALSE; 01387 01388 if (g_list_length (q1->terms) != g_list_length (q2->terms)) return FALSE; 01389 if (q1->max_results != q2->max_results) return FALSE; 01390 01391 for (or1 = q1->terms, or2 = q2->terms; or1; 01392 or1 = or1->next, or2 = or2->next) 01393 { 01394 GList *and1, *and2; 01395 01396 and1 = or1->data; 01397 and2 = or2->data; 01398 01399 if (g_list_length (and1) != g_list_length (and2)) return FALSE; 01400 01401 for ( ; and1; and1 = and1->next, and2 = and2->next) 01402 if (!qof_query_term_equal (and1->data, and2->data)) 01403 return FALSE; 01404 } 01405 01406 if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort))) 01407 return FALSE; 01408 if (!qof_query_sort_equal (&(q1->secondary_sort), &(q2->secondary_sort))) 01409 return FALSE; 01410 if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort))) 01411 return FALSE; 01412 01413 return TRUE; 01414 }
|
|
|
Return the list of books we're using Definition at line 1251 of file qofquery.c. 01252 { 01253 if (!q) return NULL; 01254 return q->books; 01255 }
|
|
|
Return the type of data we're querying for Definition at line 1289 of file qofquery.c. 01290 { 01291 if (!q) return NULL; 01292 return q->search_for; 01293 }
|
|
||||||||||||
|
DOCUMENT ME !! Definition at line 878 of file qofquery.c. 00879 { 00880 GList *or; 00881 GList *and; 00882 00883 if (!q || !term_param) 00884 return FALSE; 00885 00886 for(or = q->terms; or; or = or->next) { 00887 for(and = or->data; and; and = and->next) { 00888 QofQueryTerm *qt = and->data; 00889 if (!param_list_cmp (term_param, qt->param_list)) 00890 return TRUE; 00891 } 00892 } 00893 00894 return FALSE; 00895 }
|
|
|
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 862 of file qofquery.c. 00863 { 00864 if (!q) return 0; 00865 return g_list_length (q->terms); 00866 }
|
|
|
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 1270 of file qofquery.c. 01271 { 01272 ENTER (" "); 01273 qof_query_core_init (); 01274 qof_class_init (); 01275 }
|
|
|
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 958 of file qofquery.c. 00959 { 00960 QofQuery * retval; 00961 QofQuery * right, * left, * iright, * ileft; 00962 QofQueryTerm * qt; 00963 GList * aterms; 00964 GList * cur; 00965 GList * new_oterm; 00966 int num_or_terms; 00967 00968 if (!q) 00969 return NULL; 00970 00971 num_or_terms = g_list_length(q->terms); 00972 00973 switch(num_or_terms) 00974 { 00975 case 0: 00976 retval = qof_query_create(); 00977 retval->max_results = q->max_results; 00978 break; 00979 00980 /* This is the DeMorgan expansion for a single AND expression. */ 00981 /* !(abc) = !a + !b + !c */ 00982 case 1: 00983 retval = qof_query_create(); 00984 retval->max_results = q->max_results; 00985 retval->books = g_list_copy (q->books); 00986 retval->search_for = q->search_for; 00987 retval->changed = 1; 00988 00989 aterms = g_list_nth_data(q->terms, 0); 00990 new_oterm = NULL; 00991 for(cur=aterms; cur; cur=cur->next) { 00992 qt = copy_query_term(cur->data); 00993 qt->invert = !(qt->invert); 00994 new_oterm = g_list_append(NULL, qt); 00995 00996 /* g_list_append() can take forever, so let's do this for speed 00997 * in "large" queries. 00998 */ 00999 retval->terms = g_list_reverse(retval->terms); 01000 retval->terms = g_list_prepend(retval->terms, new_oterm); 01001 retval->terms = g_list_reverse(retval->terms); 01002 } 01003 break; 01004 01005 /* If there are multiple OR-terms, we just recurse by 01006 * breaking it down to !(a + b + c) = 01007 * !a * !(b + c) = !a * !b * !c. */ 01008 default: 01009 right = qof_query_create(); 01010 right->terms = copy_or_terms(g_list_nth(q->terms, 1)); 01011 01012 left = qof_query_create(); 01013 left->terms = g_list_append(NULL, 01014 copy_and_terms(g_list_nth_data(q->terms, 0))); 01015 01016 iright = qof_query_invert(right); 01017 ileft = qof_query_invert(left); 01018 01019 retval = qof_query_merge(iright, ileft, QOF_QUERY_AND); 01020 retval->books = g_list_copy (q->books); 01021 retval->max_results = q->max_results; 01022 retval->search_for = q->search_for; 01023 retval->changed = 1; 01024 01025 qof_query_destroy(iright); 01026 qof_query_destroy(ileft); 01027 qof_query_destroy(right); 01028 qof_query_destroy(left); 01029 break; 01030 } 01031 01032 return retval; 01033 }
|
|
||||||||||||||||
|
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 812 of file qofquery.c. 00813 { 00814 if (!query) 00815 return NULL; 00816 00817 return query->results; 00818 }
|
|
||||||||||||||||
|
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 1041 of file qofquery.c. 01042 { 01043 01044 QofQuery * retval = NULL; 01045 QofQuery * i1, * i2; 01046 QofQuery * t1, * t2; 01047 GList * i, * j; 01048 QofIdType search_for; 01049 01050 if(!q1) return q2; 01051 if(!q2) return q1; 01052 01053 if (q1->search_for && q2->search_for) 01054 g_return_val_if_fail (safe_strcmp (q1->search_for, q2->search_for) == 0, 01055 NULL); 01056 01057 search_for = (q1->search_for ? q1->search_for : q2->search_for); 01058 01059 /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty. 01060 * The goal of this tweak is to all the user to start with 01061 * an empty q1 and then append to it recursively 01062 * (and q1 (and q2 (and q3 (and q4 ....)))) 01063 * without bombing out because the append started with an 01064 * empty list. 01065 * We do essentially the same check in qof_query_add_term() 01066 * so that the first term added to an empty query doesn't screw up. 01067 */ 01068 if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1))) 01069 { 01070 op = QOF_QUERY_OR; 01071 } 01072 01073 switch(op) 01074 { 01075 case QOF_QUERY_OR: 01076 retval = qof_query_create(); 01077 retval->terms = 01078 g_list_concat(copy_or_terms(q1->terms), copy_or_terms(q2->terms)); 01079 retval->books = merge_books (q1->books, q2->books); 01080 retval->max_results = q1->max_results; 01081 retval->changed = 1; 01082 break; 01083 01084 case QOF_QUERY_AND: 01085 retval = qof_query_create(); 01086 retval->books = merge_books (q1->books, q2->books); 01087 retval->max_results = q1->max_results; 01088 retval->changed = 1; 01089 01090 /* g_list_append() can take forever, so let's build the list in 01091 * reverse and then reverse it at the end, to deal better with 01092 * "large" queries. 01093 */ 01094 for(i=q1->terms; i; i=i->next) 01095 { 01096 for(j=q2->terms; j; j=j->next) 01097 { 01098 retval->terms = 01099 g_list_prepend(retval->terms, 01100 g_list_concat 01101 (copy_and_terms(i->data), 01102 copy_and_terms(j->data))); 01103 } 01104 } 01105 retval->terms = g_list_reverse(retval->terms); 01106 break; 01107 01108 case QOF_QUERY_NAND: 01109 /* !(a*b) = (!a + !b) */ 01110 i1 = qof_query_invert(q1); 01111 i2 = qof_query_invert(q2); 01112 retval = qof_query_merge(i1, i2, QOF_QUERY_OR); 01113 qof_query_destroy(i1); 01114 qof_query_destroy(i2); 01115 break; 01116 01117 case QOF_QUERY_NOR: 01118 /* !(a+b) = (!a*!b) */ 01119 i1 = qof_query_invert(q1); 01120 i2 = qof_query_invert(q2); 01121 retval = qof_query_merge(i1, i2, QOF_QUERY_AND); 01122 qof_query_destroy(i1); 01123 qof_query_destroy(i2); 01124 break; 01125 01126 case QOF_QUERY_XOR: 01127 /* a xor b = (a * !b) + (!a * b) */ 01128 i1 = qof_query_invert(q1); 01129 i2 = qof_query_invert(q2); 01130 t1 = qof_query_merge(q1, i2, QOF_QUERY_AND); 01131 t2 = qof_query_merge(i1, q2, QOF_QUERY_AND); 01132 retval = qof_query_merge(t1, t2, QOF_QUERY_OR); 01133 01134 qof_query_destroy(i1); 01135 qof_query_destroy(i2); 01136 qof_query_destroy(t1); 01137 qof_query_destroy(t2); 01138 break; 01139 } 01140 01141 retval->search_for = search_for; 01142 return retval; 01143 }
|
|
||||||||||||||||
|
Like qof_query_merge, but this will merge a copy of q2 into q1. q2 remains unchanged. Definition at line 1146 of file qofquery.c. 01147 { 01148 QofQuery *tmp_q; 01149 01150 if (!q1 || !q2) 01151 return; 01152 01153 tmp_q = qof_query_merge (q1, q2, op); 01154 swap_terms (q1, tmp_q); 01155 qof_query_destroy (tmp_q); 01156 }
|
|
|
Return the number of terms in the canonical form of the query. Definition at line 868 of file qofquery.c. 00869 { 00870 GList *o; 00871 int n = 0; 00872 if (!q) return 0; 00873 for (o = q->terms; o; o=o->next) 00874 n += g_list_length(o->data); 00875 return n; 00876 }
|
|
|
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 669 of file qofquery.c. 00670 { 00671 QofQueryTerm *qt; 00672 GList *or, *and; 00673 00674 if (!q || !param_list) return; 00675 00676 for (or = q->terms; or; or = or->next) { 00677 for (and = or->data; and; and = and->next) { 00678 qt = and->data; 00679 if (!param_list_cmp (qt->param_list, param_list)) { 00680 if (g_list_length (or->data) == 1) { 00681 q->terms = g_list_remove_link (q->terms, or); 00682 g_list_free_1 (or); 00683 or = q->terms; 00684 break; 00685 } else { 00686 or->data = g_list_remove_link (or->data, and); 00687 g_list_free_1 (and); 00688 and = or->data; 00689 if (!and) break; 00690 } 00691 q->changed = 1; 00692 free_query_term (qt); 00693 } 00694 } 00695 if (!or) break; 00696 } 00697 }
|
|
|
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 699 of file qofquery.c. 00700 { 00701 GList *matching_objects = NULL; 00702 GList *node; 00703 int object_count = 0; 00704 00705 ENTER (" q=%p", q); 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 00710 /* XXX: Prioritize the query terms? */ 00711 00712 /* prepare the Query for processing */ 00713 if (q->changed) 00714 { 00715 query_clear_compiles (q); 00716 compile_terms (q); 00717 } 00718 00719 /* Maybe log this sucker */ 00720 if (gnc_should_log (module, GNC_LOG_DETAIL)) qof_query_print (q); 00721 00722 /* Now run the query over all the objects and save the results */ 00723 { 00724 QofQueryCB qcb; 00725 00726 memset (&qcb, 0, sizeof (qcb)); 00727 qcb.query = q; 00728 00729 /* For each book */ 00730 for (node=q->books; node; node=node->next) 00731 { 00732 QofBook *book = node->data; 00733 QofBackend *be = book->backend; 00734 00735 /* run the query in the backend */ 00736 if (be) 00737 { 00738 gpointer compiled_query = g_hash_table_lookup (q->be_compiled, book); 00739 00740 if (compiled_query && be->run_query) 00741 { 00742 (be->run_query) (be, compiled_query); 00743 } 00744 } 00745 00746 /* And then iterate over all the objects */ 00747 qof_object_foreach (q->search_for, book, (QofEntityForeachCB) check_item_cb, &qcb); 00748 } 00749 00750 matching_objects = qcb.list; 00751 object_count = qcb.count; 00752 } 00753 PINFO ("matching objects=%p count=%d", matching_objects, object_count); 00754 00755 /* There is no absolute need to reverse this list, since it's being 00756 * sorted below. However, in the common case, we will be searching 00757 * in a confined location where the objects are already in order, 00758 * thus reversing will put us in the correct order we want and make 00759 * the sorting go much faster. 00760 */ 00761 matching_objects = g_list_reverse(matching_objects); 00762 00763 /* Now sort the matching objects based on the search criteria 00764 * sortQuery is an unforgivable use of static global data... 00765 * I just can't figure out how else to do this sanely. 00766 */ 00767 if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp || 00768 (q->primary_sort.use_default && q->defaultSort)) 00769 { 00770 sortQuery = q; 00771 matching_objects = g_list_sort(matching_objects, sort_func); 00772 sortQuery = NULL; 00773 } 00774 00775 /* Crop the list to limit the number of splits. */ 00776 if((object_count > q->max_results) && (q->max_results > -1)) 00777 { 00778 if(q->max_results > 0) 00779 { 00780 GList *mptr; 00781 00782 /* mptr is set to the first node of what will be the new list */ 00783 mptr = g_list_nth(matching_objects, object_count - q->max_results); 00784 /* mptr should not be NULL, but let's be safe */ 00785 if (mptr != NULL) 00786 { 00787 if (mptr->prev != NULL) mptr->prev->next = NULL; 00788 mptr->prev = NULL; 00789 } 00790 g_list_free(matching_objects); 00791 matching_objects = mptr; 00792 } 00793 else 00794 { 00795 /* q->max_results == 0 */ 00796 g_list_free(matching_objects); 00797 matching_objects = NULL; 00798 } 00799 object_count = q->max_results; 00800 } 00801 00802 q->changed = 0; 00803 00804 g_list_free(q->results); 00805 q->results = matching_objects; 00806 00807 LEAVE (" q=%p", q); 00808 return matching_objects; 00809 }
|
|
||||||||||||
|
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 841 of file qofquery.c. 00842 { 00843 if (!q || !obj_type) 00844 return; 00845 00846 if (safe_strcmp (q->search_for, obj_type)) { 00847 q->search_for = (QofIdType) obj_type; 00848 q->changed = 1; 00849 } 00850 }
|
|
||||||||||||
|
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 1236 of file qofquery.c. 01237 { 01238 GSList *slist = NULL; 01239 if (!q || !book) return; 01240 01241 /* Make sure this book is only in the list once */ 01242 if (g_list_index (q->books, book) == -1) 01243 q->books = g_list_prepend (q->books, book); 01244 01245 g_slist_prepend (slist, QOF_PARAM_GUID); 01246 g_slist_prepend (slist, QOF_PARAM_BOOK); 01247 qof_query_add_guid_match (q, slist, 01248 qof_book_get_guid(book), QOF_QUERY_AND); 01249 }
|
|
||||||||||||
|
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 1199 of file qofquery.c. 01200 { 01201 if (!q) return; 01202 q->max_results = n; 01203 }
|
|
||||||||||||||||||||
|
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 1190 of file qofquery.c. 01192 { 01193 if (!q) return; 01194 q->primary_sort.increasing = prim_inc; 01195 q->secondary_sort.increasing = sec_inc; 01196 q->tertiary_sort.increasing = tert_inc; 01197 }
|
|
||||||||||||||||||||
|
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 1159 of file qofquery.c. 01161 { 01162 if (!q) return; 01163 if (q->primary_sort.param_list) 01164 g_slist_free (q->primary_sort.param_list); 01165 q->primary_sort.param_list = params1; 01166 q->primary_sort.options = 0; 01167 01168 if (q->secondary_sort.param_list) 01169 g_slist_free (q->secondary_sort.param_list); 01170 q->secondary_sort.param_list = params2; 01171 q->secondary_sort.options = 0; 01172 01173 if (q->tertiary_sort.param_list) 01174 g_slist_free (q->tertiary_sort.param_list); 01175 q->tertiary_sort.param_list = params3; 01176 q->tertiary_sort.options = 0; 01177 01178 q->changed = 1; 01179 }
|
1.4.3-20050530