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 function. 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.
Files | |
file | qofquery.h |
find objects that match a certain expression. | |
file | qofquerycore.h |
API for providing core Query data types. | |
file | qofsql.h |
QOF client-side SQL parser, interfacing with libgda. | |
Modules | |
SQL Interface to Query | |
Data Structures | |
struct | _QofQueryPredData |
Query Subsystem Initialization and Shudown | |
void | qof_query_init (void) |
void | qof_query_shutdown (void) |
Low-Level API Functions | |
GSList * | qof_query_build_param_list (gchar const *param,...) |
QofQuery * | qof_query_create (void) |
QofQuery * | qof_query_create_for (QofIdTypeConst obj_type) |
void | qof_query_destroy (QofQuery *q) |
void | qof_query_search_for (QofQuery *query, QofIdTypeConst obj_type) |
void | qof_query_set_book (QofQuery *q, QofBook *book) |
void | qof_query_add_term (QofQuery *query, GSList *param_list, QofQueryPredData *pred_data, QofQueryOp op) |
void | qof_query_add_guid_match (QofQuery *q, GSList *param_list, const GUID *guid, QofQueryOp op) |
void | qof_query_add_guid_list_match (QofQuery *q, GSList *param_list, GList *guid_list, QofGuidMatch options, QofQueryOp op) |
void | qof_query_add_boolean_match (QofQuery *q, GSList *param_list, gboolean value, QofQueryOp op) |
GList * | qof_query_run (QofQuery *query) |
GList * | qof_query_last_run (QofQuery *query) |
void | qof_query_clear (QofQuery *query) |
void | qof_query_purge_terms (QofQuery *q, GSList *param_list) |
gint | qof_query_has_terms (QofQuery *q) |
gint | qof_query_num_terms (QofQuery *q) |
gboolean | qof_query_has_term_type (QofQuery *q, GSList *term_param) |
GSList * | qof_query_get_term_type (QofQuery *q, GSList *term_param) |
QofQuery * | qof_query_copy (QofQuery *q) |
QofQuery * | qof_query_invert (QofQuery *q) |
QofQuery * | qof_query_merge (QofQuery *q1, QofQuery *q2, QofQueryOp op) |
void | qof_query_merge_in_place (QofQuery *q1, QofQuery *q2, QofQueryOp op) |
void | qof_query_set_sort_order (QofQuery *q, GSList *primary_sort_params, GSList *secondary_sort_params, GSList *tertiary_sort_params) |
void | qof_query_set_sort_options (QofQuery *q, gint prim_op, gint sec_op, gint tert_op) |
void | qof_query_set_sort_increasing (QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc) |
void | qof_query_set_max_results (QofQuery *q, gint n) |
gboolean | qof_query_equal (QofQuery *q1, QofQuery *q2) |
QofIdType | qof_query_get_search_for (QofQuery *q) |
GList * | qof_query_get_books (QofQuery *q) |
Core Data Type Predicates | |
QofQueryPredData * | qof_query_string_predicate (QofQueryCompare how, const gchar *str, QofStringMatch options, gboolean is_regex) |
QofQueryPredData * | qof_query_time_predicate (QofQueryCompare how, QofDateMatch options, QofTime *qt) |
QofQueryPredData * | qof_query_numeric_predicate (QofQueryCompare how, QofNumericMatch options, gnc_numeric value) |
QofQueryPredData * | qof_query_guid_predicate (QofGuidMatch options, GList *guids) |
QofQueryPredData * | qof_query_int32_predicate (QofQueryCompare how, gint32 val) |
QofQueryPredData * | qof_query_int64_predicate (QofQueryCompare how, gint64 val) |
QofQueryPredData * | qof_query_double_predicate (QofQueryCompare how, double val) |
QofQueryPredData * | qof_query_boolean_predicate (QofQueryCompare how, gboolean val) |
QofQueryPredData * | qof_query_char_predicate (QofCharMatch options, const gchar *chars) |
QofQueryPredData * | qof_query_collect_predicate (QofGuidMatch options, QofCollection *coll) |
QofQueryPredData * | qof_query_choice_predicate (QofGuidMatch options, GList *guids) |
QofQueryPredData * | qof_query_kvp_predicate (QofQueryCompare how, GSList *path, const KvpValue *value) |
QofQueryPredData * | qof_query_kvp_predicate_path (QofQueryCompare how, const gchar *path, const KvpValue *value) |
QofQueryPredData * | qof_query_core_predicate_copy (QofQueryPredData *pdata) |
void | qof_query_core_predicate_free (QofQueryPredData *pdata) |
gboolean | qof_query_time_predicate_get_time (QofQueryPredData *pd, QofTime *qt) |
gchar * | qof_query_core_to_string (QofType, gpointer object, QofParam *getter) |
Defines | |
#define | QOF_MOD_QUERY "qof-query" |
#define | QOF_QUERY_FIRST_TERM QOF_QUERY_AND |
#define | QUERY_DEFAULT_SORT "QofQueryDefaultSort" |
#define | QOF_PARAM_BOOK "book" |
#define | QOF_PARAM_GUID "guid" |
#define | QOF_PARAM_KVP "kvp" |
#define | QOF_PARAM_ACTIVE "active" |
#define | QOF_PARAM_VERSION "version" |
Typedefs | |
typedef _QofQuery | QofQuery |
typedef _QofQueryPredData | QofQueryPredData |
Enumerations | |
enum | QofQueryOp { QOF_QUERY_AND = 1, QOF_QUERY_OR, QOF_QUERY_NAND, QOF_QUERY_NOR, QOF_QUERY_XOR } |
enum | QofQueryCompare { QOF_COMPARE_LT = 1, QOF_COMPARE_LTE, QOF_COMPARE_EQUAL, QOF_COMPARE_GT, QOF_COMPARE_GTE, QOF_COMPARE_NEQ } |
enum | QofStringMatch { QOF_STRING_MATCH_NORMAL = 1, QOF_STRING_MATCH_CASEINSENSITIVE } |
enum | QofDateMatch { QOF_DATE_MATCH_NORMAL = 1, QOF_DATE_MATCH_DAY } |
enum | QofNumericMatch { QOF_NUMERIC_MATCH_DEBIT = 1, QOF_NUMERIC_MATCH_CREDIT, QOF_NUMERIC_MATCH_ANY } |
enum | QofGuidMatch { QOF_GUID_MATCH_ANY = 1, QOF_GUID_MATCH_NONE, QOF_GUID_MATCH_NULL, QOF_GUID_MATCH_ALL, QOF_GUID_MATCH_LIST_ANY } |
enum | QofCharMatch { QOF_CHAR_MATCH_ANY = 1, QOF_CHAR_MATCH_NONE } |
#define QOF_PARAM_BOOK "book" |
"Known" Object Parameters -- all objects must support these
Definition at line 104 of file qofquery.h.
#define QOF_PARAM_KVP "kvp" |
"Known" Object Parameters -- some objects might support these
Definition at line 108 of file qofquery.h.
#define QOF_QUERY_FIRST_TERM QOF_QUERY_AND |
First/only term is same as 'and'
Definition at line 98 of file qofquery.h.
#define QUERY_DEFAULT_SORT "QofQueryDefaultSort" |
Default sort object type
Definition at line 101 of file qofquery.h.
typedef struct _QofQuery QofQuery |
A Query
Definition at line 85 of file qofquery.h.
typedef struct _QofQueryPredData QofQueryPredData |
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 46 of file qofquerycore.h.
enum QofCharMatch |
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 127 of file qofquerycore.h.
00128 { 00129 QOF_CHAR_MATCH_ANY = 1, 00130 QOF_CHAR_MATCH_NONE 00131 } QofCharMatch;
enum QofDateMatch |
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 78 of file qofquerycore.h.
00079 { 00080 QOF_DATE_MATCH_NORMAL = 1, 00081 QOF_DATE_MATCH_DAY 00082 } QofDateMatch;
enum QofGuidMatch |
Definition at line 104 of file qofquerycore.h.
00105 { 00108 QOF_GUID_MATCH_ANY = 1, 00109 QOF_GUID_MATCH_NONE, 00110 QOF_GUID_MATCH_NULL, 00113 QOF_GUID_MATCH_ALL, 00116 QOF_GUID_MATCH_LIST_ANY, 00117 } QofGuidMatch;
enum QofNumericMatch |
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 96 of file qofquerycore.h.
00097 { 00098 QOF_NUMERIC_MATCH_DEBIT = 1, 00099 QOF_NUMERIC_MATCH_CREDIT, 00100 QOF_NUMERIC_MATCH_ANY 00101 } QofNumericMatch;
enum QofQueryCompare |
Standard Query comparitors, for how to compare objects in a predicate. Note that not all core types implement all comparitors
Definition at line 51 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;
enum QofQueryOp |
Query Term Operators, for combining Query Terms
Definition at line 88 of file qofquery.h.
00089 { 00090 QOF_QUERY_AND = 1, 00091 QOF_QUERY_OR, 00092 QOF_QUERY_NAND, 00093 QOF_QUERY_NOR, 00094 QOF_QUERY_XOR 00095 } QofQueryOp;
enum QofStringMatch |
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.
00066 { 00067 QOF_STRING_MATCH_NORMAL = 1, 00068 QOF_STRING_MATCH_CASEINSENSITIVE 00069 } QofStringMatch;
void qof_query_add_boolean_match | ( | QofQuery * | q, | |
GSList * | param_list, | |||
gboolean | value, | |||
QofQueryOp | op | |||
) |
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 1359 of file qofquery.c.
01361 { 01362 QofQueryPredData *pdata; 01363 if (!q || !param_list) 01364 return; 01365 01366 pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value); 01367 qof_query_add_term (q, param_list, pdata, op); 01368 }
void qof_query_add_guid_list_match | ( | QofQuery * | q, | |
GSList * | param_list, | |||
GList * | guid_list, | |||
QofGuidMatch | options, | |||
QofQueryOp | op | |||
) |
DOCUMENT ME !!
Definition at line 1300 of file qofquery.c.
01302 { 01303 QofQueryPredData *pdata; 01304 01305 if (!q || !param_list) 01306 return; 01307 01308 if (!guid_list) 01309 g_return_if_fail (options == QOF_GUID_MATCH_NULL); 01310 01311 pdata = qof_query_guid_predicate (options, guid_list); 01312 qof_query_add_term (q, param_list, pdata, op); 01313 }
void qof_query_add_guid_match | ( | QofQuery * | q, | |
GSList * | param_list, | |||
const GUID * | guid, | |||
QofQueryOp | op | |||
) |
DOCUMENT ME !!
Definition at line 1316 of file qofquery.c.
01318 { 01319 GList *g = NULL; 01320 01321 if (!q || !param_list) 01322 return; 01323 01324 if (guid) 01325 g = g_list_prepend (g, (gpointer) guid); 01326 01327 qof_query_add_guid_list_match (q, param_list, g, 01328 g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op); 01329 01330 g_list_free (g); 01331 }
void qof_query_add_term | ( | QofQuery * | query, | |
GSList * | param_list, | |||
QofQueryPredData * | pred_data, | |||
QofQueryOp | op | |||
) |
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 comparator. The param_list is a recursive list of parameters. The list becomes the property of the Query.
QofQueryPredData *time_pred_data; QofQuery *query; QofParam *param; QofTime *qoftime; time_pred_data = qof_query_time_predicate (QOF_COMPARE_GTE, QOF_DATE_MATCH_DAY, qoftime); qof_query_add_term (query, qof_query_build_param_list ((gchar*)param->param_name, NULL), time_pred_data, QOF_QUERY_AND);
Definition at line 690 of file qofquery.c.
00692 { 00693 QofQueryTerm *qt; 00694 QofQuery *qr, *qs; 00695 00696 if (!q || !param_list || !pred_data) 00697 return; 00698 00699 qt = g_new0 (QofQueryTerm, 1); 00700 qt->param_list = param_list; 00701 qt->pdata = pred_data; 00702 qs = qof_query_create (); 00703 query_init (qs, qt); 00704 00705 if (qof_query_has_terms (q)) 00706 qr = qof_query_merge (q, qs, op); 00707 else 00708 qr = qof_query_merge (q, qs, QOF_QUERY_OR); 00709 00710 swap_terms (q, qr); 00711 qof_query_destroy (qs); 00712 qof_query_destroy (qr); 00713 }
void qof_query_clear | ( | QofQuery * | query | ) |
Remove all query terms from query. query matches nothing after qof_query_clear().
Definition at line 885 of file qofquery.c.
00886 { 00887 QofQuery *q2 = qof_query_create (); 00888 swap_terms (query, q2); 00889 qof_query_destroy (q2); 00890 00891 g_list_free (query->books); 00892 query->books = NULL; 00893 g_list_free (query->results); 00894 query->results = NULL; 00895 query->changed = 1; 00896 }
Make a copy of the indicated query
Definition at line 1008 of file qofquery.c.
01009 { 01010 QofQuery *copy; 01011 GHashTable *ht; 01012 01013 if (!q) 01014 return NULL; 01015 copy = qof_query_create (); 01016 ht = copy->be_compiled; 01017 free_members (copy); 01018 01019 memcpy (copy, q, sizeof (QofQuery)); 01020 01021 copy->be_compiled = ht; 01022 copy->terms = copy_or_terms (q->terms); 01023 copy->books = g_list_copy (q->books); 01024 copy->results = g_list_copy (q->results); 01025 01026 copy_sort (&(copy->primary_sort), &(q->primary_sort)); 01027 copy_sort (&(copy->secondary_sort), &(q->secondary_sort)); 01028 copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort)); 01029 01030 copy->changed = 1; 01031 01032 return copy; 01033 }
QofQueryPredData* qof_query_core_predicate_copy | ( | QofQueryPredData * | pdata | ) |
Copy a predicate.
Definition at line 2105 of file qofquerycore.c.
void qof_query_core_predicate_free | ( | QofQueryPredData * | pdata | ) |
Destroy a predicate.
Definition at line 2093 of file qofquerycore.c.
Return a printable string for a core data object. Caller needs to g_free() the returned string.
Definition at line 2117 of file qofquerycore.c.
QofQuery* qof_query_create | ( | void | ) |
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 899 of file qofquery.c.
00900 { 00901 QofQuery *qp = g_new0 (QofQuery, 1); 00902 qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal); 00903 query_init (qp, NULL); 00904 return qp; 00905 }
QofQuery* qof_query_create_for | ( | QofIdTypeConst | obj_type | ) |
create a query with a search type preset.
Definition at line 921 of file qofquery.c.
00922 { 00923 QofQuery *q; 00924 if (!obj_type) 00925 return NULL; 00926 q = qof_query_create (); 00927 qof_query_search_for (q, obj_type); 00928 return q; 00929 }
void qof_query_destroy | ( | QofQuery * | q | ) |
Frees the resources associated with a Query object.
Definition at line 997 of file qofquery.c.
00998 { 00999 if (!q) 01000 return; 01001 free_members (q); 01002 query_clear_compiles (q); 01003 g_hash_table_destroy (q->be_compiled); 01004 g_free (q); 01005 }
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 1510 of file qofquery.c.
01511 { 01512 GList *or1, *or2; 01513 01514 if (q1 == q2) 01515 return TRUE; 01516 if (!q1 || !q2) 01517 return FALSE; 01518 01519 if (g_list_length (q1->terms) != g_list_length (q2->terms)) 01520 return FALSE; 01521 if (q1->max_results != q2->max_results) 01522 return FALSE; 01523 01524 for (or1 = q1->terms, or2 = q2->terms; or1; 01525 or1 = or1->next, or2 = or2->next) 01526 { 01527 GList *and1, *and2; 01528 01529 and1 = or1->data; 01530 and2 = or2->data; 01531 01532 if (g_list_length (and1) != g_list_length (and2)) 01533 return FALSE; 01534 01535 for (; and1; and1 = and1->next, and2 = and2->next) 01536 if (!qof_query_term_equal (and1->data, and2->data)) 01537 return FALSE; 01538 } 01539 01540 if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort))) 01541 return FALSE; 01542 if (!qof_query_sort_equal (&(q1->secondary_sort), 01543 &(q2->secondary_sort))) 01544 return FALSE; 01545 if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort))) 01546 return FALSE; 01547 01548 return TRUE; 01549 }
GList* qof_query_get_books | ( | QofQuery * | q | ) |
gboolean qof_query_has_term_type | ( | QofQuery * | q, | |
GSList * | term_param | |||
) |
DOCUMENT ME !!
Definition at line 952 of file qofquery.c.
00953 { 00954 GList *or; 00955 GList *and; 00956 00957 if (!q || !term_param) 00958 return FALSE; 00959 00960 for (or = q->terms; or; or = or->next) 00961 { 00962 for (and = or->data; and; and = and->next) 00963 { 00964 QofQueryTerm *qt = and->data; 00965 if (!param_list_cmp (term_param, qt->param_list)) 00966 return TRUE; 00967 } 00968 } 00969 00970 return FALSE; 00971 }
gint qof_query_has_terms | ( | QofQuery * | q | ) |
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 932 of file qofquery.c.
void qof_query_init | ( | void | ) |
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 1374 of file qofquery.c.
01375 { 01376 ENTER (" "); 01377 qof_query_core_init (); 01378 qof_class_init (); 01379 LEAVE ("Completed initialization of QofQuery"); 01380 }
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 1042 of file qofquery.c.
01043 { 01044 QofQuery *retval; 01045 QofQuery *right, *left, *iright, *ileft; 01046 QofQueryTerm *qt; 01047 GList *aterms; 01048 GList *cur; 01049 GList *new_oterm; 01050 gint num_or_terms; 01051 01052 if (!q) 01053 return NULL; 01054 01055 num_or_terms = g_list_length (q->terms); 01056 01057 switch (num_or_terms) 01058 { 01059 case 0: 01060 retval = qof_query_create (); 01061 retval->max_results = q->max_results; 01062 break; 01063 01064 /* This is the DeMorgan expansion for a single AND expression. */ 01065 /* !(abc) = !a + !b + !c */ 01066 case 1: 01067 retval = qof_query_create (); 01068 retval->max_results = q->max_results; 01069 retval->books = g_list_copy (q->books); 01070 retval->search_for = q->search_for; 01071 retval->changed = 1; 01072 01073 aterms = g_list_nth_data (q->terms, 0); 01074 new_oterm = NULL; 01075 for (cur = aterms; cur; cur = cur->next) 01076 { 01077 qt = copy_query_term (cur->data); 01078 qt->invert = !(qt->invert); 01079 new_oterm = g_list_append (NULL, qt); 01080 01081 /* g_list_append() can take forever, so let's do this for speed 01082 * in "large" queries. 01083 */ 01084 retval->terms = g_list_reverse (retval->terms); 01085 retval->terms = g_list_prepend (retval->terms, new_oterm); 01086 retval->terms = g_list_reverse (retval->terms); 01087 } 01088 break; 01089 01090 /* If there are multiple OR-terms, we just recurse by 01091 * breaking it down to !(a + b + c) = 01092 * !a * !(b + c) = !a * !b * !c. */ 01093 default: 01094 right = qof_query_create (); 01095 right->terms = copy_or_terms (g_list_nth (q->terms, 1)); 01096 01097 left = qof_query_create (); 01098 left->terms = g_list_append (NULL, 01099 copy_and_terms (g_list_nth_data (q->terms, 0))); 01100 01101 iright = qof_query_invert (right); 01102 ileft = qof_query_invert (left); 01103 01104 retval = qof_query_merge (iright, ileft, QOF_QUERY_AND); 01105 retval->books = g_list_copy (q->books); 01106 retval->max_results = q->max_results; 01107 retval->search_for = q->search_for; 01108 retval->changed = 1; 01109 01110 qof_query_destroy (iright); 01111 qof_query_destroy (ileft); 01112 qof_query_destroy (right); 01113 qof_query_destroy (left); 01114 break; 01115 } 01116 01117 return retval; 01118 }
QofQueryPredData* qof_query_kvp_predicate | ( | QofQueryCompare | how, | |
GSList * | path, | |||
const KvpValue * | value | |||
) |
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 1310 of file qofquerycore.c.
01321 { 01322 spath = g_slist_append (spath, p); 01323 p = strchr (p, '/'); 01324 if (p) 01325 { 01326 *p = 0; 01327 p++;
QofQueryPredData* qof_query_kvp_predicate_path | ( | QofQueryCompare | how, | |
const gchar * | path, | |||
const KvpValue * | value | |||
) |
Same predicate as above, except that 'path' is assumed to be a string containing slash-separated pathname.
GList* qof_query_last_run | ( | QofQuery * | query | ) |
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 876 of file qofquery.c.
QofQuery* qof_query_merge | ( | QofQuery * | q1, | |
QofQuery * | q2, | |||
QofQueryOp | op | |||
) |
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 1126 of file qofquery.c.
01127 { 01128 01129 QofQuery *retval = NULL; 01130 QofQuery *i1, *i2; 01131 QofQuery *t1, *t2; 01132 GList *i, *j; 01133 QofIdType search_for; 01134 01135 if (!q1) 01136 return q2; 01137 if (!q2) 01138 return q1; 01139 01140 if (q1->search_for && q2->search_for) 01141 g_return_val_if_fail (safe_strcmp (q1->search_for, 01142 q2->search_for) == 0, NULL); 01143 01144 search_for = (q1->search_for ? q1->search_for : q2->search_for); 01145 01146 /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty. 01147 * The goal of this tweak is to all the user to start with 01148 * an empty q1 and then append to it recursively 01149 * (and q1 (and q2 (and q3 (and q4 ....)))) 01150 * without bombing out because the append started with an 01151 * empty list. 01152 * We do essentially the same check in qof_query_add_term() 01153 * so that the first term added to an empty query doesn't screw up. 01154 */ 01155 if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1))) 01156 { 01157 op = QOF_QUERY_OR; 01158 } 01159 01160 switch (op) 01161 { 01162 case QOF_QUERY_OR: 01163 retval = qof_query_create (); 01164 retval->terms = 01165 g_list_concat (copy_or_terms (q1->terms), 01166 copy_or_terms (q2->terms)); 01167 retval->books = merge_books (q1->books, q2->books); 01168 retval->max_results = q1->max_results; 01169 retval->changed = 1; 01170 break; 01171 01172 case QOF_QUERY_AND: 01173 retval = qof_query_create (); 01174 retval->books = merge_books (q1->books, q2->books); 01175 retval->max_results = q1->max_results; 01176 retval->changed = 1; 01177 01178 /* g_list_append() can take forever, so let's build the list in 01179 * reverse and then reverse it at the end, to deal better with 01180 * "large" queries. 01181 */ 01182 for (i = q1->terms; i; i = i->next) 01183 { 01184 for (j = q2->terms; j; j = j->next) 01185 { 01186 retval->terms = 01187 g_list_prepend (retval->terms, 01188 g_list_concat 01189 (copy_and_terms (i->data), copy_and_terms (j->data))); 01190 } 01191 } 01192 retval->terms = g_list_reverse (retval->terms); 01193 break; 01194 01195 case QOF_QUERY_NAND: 01196 /* !(a*b) = (!a + !b) */ 01197 i1 = qof_query_invert (q1); 01198 i2 = qof_query_invert (q2); 01199 retval = qof_query_merge (i1, i2, QOF_QUERY_OR); 01200 qof_query_destroy (i1); 01201 qof_query_destroy (i2); 01202 break; 01203 01204 case QOF_QUERY_NOR: 01205 /* !(a+b) = (!a*!b) */ 01206 i1 = qof_query_invert (q1); 01207 i2 = qof_query_invert (q2); 01208 retval = qof_query_merge (i1, i2, QOF_QUERY_AND); 01209 qof_query_destroy (i1); 01210 qof_query_destroy (i2); 01211 break; 01212 01213 case QOF_QUERY_XOR: 01214 /* a xor b = (a * !b) + (!a * b) */ 01215 i1 = qof_query_invert (q1); 01216 i2 = qof_query_invert (q2); 01217 t1 = qof_query_merge (q1, i2, QOF_QUERY_AND); 01218 t2 = qof_query_merge (i1, q2, QOF_QUERY_AND); 01219 retval = qof_query_merge (t1, t2, QOF_QUERY_OR); 01220 01221 qof_query_destroy (i1); 01222 qof_query_destroy (i2); 01223 qof_query_destroy (t1); 01224 qof_query_destroy (t2); 01225 break; 01226 } 01227 01228 retval->search_for = search_for; 01229 return retval; 01230 }
void qof_query_merge_in_place | ( | QofQuery * | q1, | |
QofQuery * | q2, | |||
QofQueryOp | op | |||
) |
Like qof_query_merge, but this will merge a copy of q2 into q1. q2 remains unchanged.
Definition at line 1233 of file qofquery.c.
01234 { 01235 QofQuery *tmp_q; 01236 01237 if (!q1 || !q2) 01238 return; 01239 01240 tmp_q = qof_query_merge (q1, q2, op); 01241 swap_terms (q1, tmp_q); 01242 qof_query_destroy (tmp_q); 01243 }
gint qof_query_num_terms | ( | QofQuery * | q | ) |
Return the number of terms in the canonical form of the query.
Definition at line 940 of file qofquery.c.
00941 { 00942 GList *o; 00943 gint n = 0; 00944 if (!q) 00945 return 0; 00946 for (o = q->terms; o; o = o->next) 00947 n += g_list_length (o->data); 00948 return n; 00949 }
void qof_query_purge_terms | ( | QofQuery * | q, | |
GSList * | param_list | |||
) |
Remove query terms of a particular QofType from the query. The "type" of a term is determined by the QofType that gets passed to the predicate function. All query terms of this type are removed.
Definition at line 716 of file qofquery.c.
00717 { 00718 QofQueryTerm *qt; 00719 GList *or, *and; 00720 00721 if (!q || !param_list) 00722 return; 00723 00724 for (or = q->terms; or; or = or->next) 00725 { 00726 for (and = or->data; and; and = and->next) 00727 { 00728 qt = and->data; 00729 if (!param_list_cmp (qt->param_list, param_list)) 00730 { 00731 if (g_list_length (or->data) == 1) 00732 { 00733 q->terms = g_list_remove_link (q->terms, or); 00734 g_list_free_1 (or); 00735 or = q->terms; 00736 break; 00737 } 00738 else 00739 { 00740 or->data = g_list_remove_link (or->data, and); 00741 g_list_free_1 (and); 00742 and = or->data; 00743 if (!and) 00744 break; 00745 } 00746 q->changed = 1; 00747 free_query_term (qt); 00748 } 00749 } 00750 if (!or) 00751 break; 00752 } 00753 }
GList* qof_query_run | ( | QofQuery * | query | ) |
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 756 of file qofquery.c.
00757 { 00758 GList *matching_objects = NULL; 00759 GList *node; 00760 gint object_count = 0; 00761 00762 if (!q) 00763 return NULL; 00764 g_return_val_if_fail (q->search_for, NULL); 00765 g_return_val_if_fail (q->books, NULL); 00766 ENTER (" q=%p", q); 00767 00768 /* XXX: Prioritize the query terms? */ 00769 00770 /* prepare the Query for processing */ 00771 if (q->changed) 00772 { 00773 query_clear_compiles (q); 00774 compile_terms (q); 00775 } 00776 00777 /* Maybe log this sucker */ 00778 if (qof_log_check (log_module, QOF_LOG_DETAIL)) 00779 qof_query_print (q); 00780 00781 /* Now run the query over all the objects and save the results */ 00782 { 00783 QofQueryCB qcb; 00784 00785 memset (&qcb, 0, sizeof (qcb)); 00786 qcb.query = q; 00787 00788 /* For each book */ 00789 for (node = q->books; node; node = node->next) 00790 { 00791 QofBook *book = node->data; 00792 QofBackend *be = book->backend; 00793 00794 /* run the query in the backend */ 00795 if (be) 00796 { 00797 gpointer compiled_query = 00798 g_hash_table_lookup (q->be_compiled, book); 00799 00800 if (compiled_query && be->run_query) 00801 { 00802 (be->run_query) (be, compiled_query); 00803 } 00804 } 00805 00806 /* And then iterate over all the objects */ 00807 qof_object_foreach (q->search_for, book, 00808 (QofEntityForeachCB) check_item_cb, &qcb); 00809 } 00810 00811 matching_objects = qcb.list; 00812 object_count = qcb.count; 00813 } 00814 PINFO ("matching objects=%p count=%d", matching_objects, object_count); 00815 00816 /* There is no absolute need to reverse this list, since it's being 00817 * sorted below. However, in the common case, we will be searching 00818 * in a confined location where the objects are already in order, 00819 * thus reversing will put us in the correct order we want and make 00820 * the sorting go much faster. 00821 */ 00822 matching_objects = g_list_reverse (matching_objects); 00823 00824 /* Now sort the matching objects based on the search criteria 00825 * sortQuery is an unforgivable use of static global data... 00826 * I just can't figure out how else to do this sanely. 00827 */ 00828 if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp || 00829 (q->primary_sort.use_default && q->defaultSort)) 00830 { 00831 sortQuery = q; 00832 matching_objects = g_list_sort (matching_objects, sort_func); 00833 sortQuery = NULL; 00834 } 00835 00836 /* Crop the list to limit the number of splits. */ 00837 if ((object_count > q->max_results) && (q->max_results > -1)) 00838 { 00839 if (q->max_results > 0) 00840 { 00841 GList *mptr; 00842 00843 /* mptr is set to the first node of what will be the new list */ 00844 mptr = 00845 g_list_nth (matching_objects, 00846 object_count - q->max_results); 00847 /* mptr should not be NULL, but let's be safe */ 00848 if (mptr != NULL) 00849 { 00850 if (mptr->prev != NULL) 00851 mptr->prev->next = NULL; 00852 mptr->prev = NULL; 00853 } 00854 g_list_free (matching_objects); 00855 matching_objects = mptr; 00856 } 00857 else 00858 { 00859 /* q->max_results == 0 */ 00860 g_list_free (matching_objects); 00861 matching_objects = NULL; 00862 } 00863 object_count = q->max_results; 00864 } 00865 00866 q->changed = 0; 00867 00868 g_list_free (q->results); 00869 q->results = matching_objects; 00870 00871 LEAVE (" q=%p", q); 00872 return matching_objects; 00873 }
void qof_query_search_for | ( | QofQuery * | query, | |
QofIdTypeConst | obj_type | |||
) |
Set the object type to be searched for. The results of performing the query will be a list of this obj_type.
Definition at line 908 of file qofquery.c.
00909 { 00910 if (!q || !obj_type) 00911 return; 00912 00913 if (safe_strcmp (q->search_for, obj_type)) 00914 { 00915 q->search_for = (QofIdType) obj_type; 00916 q->changed = 1; 00917 } 00918 }
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 1334 of file qofquery.c.
01335 { 01336 GSList *slist = NULL; 01337 if (!q || !book) 01338 return; 01339 01340 /* Make sure this book is only in the list once */ 01341 if (g_list_index (q->books, book) == -1) 01342 q->books = g_list_prepend (q->books, book); 01343 01344 slist = g_slist_prepend (slist, QOF_PARAM_GUID); 01345 slist = g_slist_prepend (slist, QOF_PARAM_BOOK); 01346 qof_query_add_guid_match (q, slist, 01347 qof_entity_get_guid ((QofEntity*)book), QOF_QUERY_AND); 01348 }
void qof_query_set_max_results | ( | QofQuery * | q, | |
gint | n | |||
) |
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 1292 of file qofquery.c.
void qof_query_set_sort_increasing | ( | QofQuery * | q, | |
gboolean | prim_inc, | |||
gboolean | sec_inc, | |||
gboolean | tert_inc | |||
) |
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 1281 of file qofquery.c.
01283 { 01284 if (!q) 01285 return; 01286 q->primary_sort.increasing = prim_inc; 01287 q->secondary_sort.increasing = sec_inc; 01288 q->tertiary_sort.increasing = tert_inc; 01289 }
void qof_query_set_sort_order | ( | QofQuery * | q, | |
GSList * | primary_sort_params, | |||
GSList * | secondary_sort_params, | |||
GSList * | tertiary_sort_params | |||
) |
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 1246 of file qofquery.c.
01248 { 01249 if (!q) 01250 return; 01251 if (q->primary_sort.param_list) 01252 g_slist_free (q->primary_sort.param_list); 01253 q->primary_sort.param_list = params1; 01254 q->primary_sort.options = 0; 01255 01256 if (q->secondary_sort.param_list) 01257 g_slist_free (q->secondary_sort.param_list); 01258 q->secondary_sort.param_list = params2; 01259 q->secondary_sort.options = 0; 01260 01261 if (q->tertiary_sort.param_list) 01262 g_slist_free (q->tertiary_sort.param_list); 01263 q->tertiary_sort.param_list = params3; 01264 q->tertiary_sort.options = 0; 01265 01266 q->changed = 1; 01267 }
gboolean qof_query_time_predicate_get_time | ( | QofQueryPredData * | pd, | |
QofTime * | qt | |||
) |
Retrieve a predicate.
Definition at line 408 of file qofquerycore.c.
00408 { 00409 query_numeric_t pdata = (query_numeric_t) pd; 00410 gnc_numeric obj_val; 00411 int compare; 00412 00413 VERIFY_PREDICATE (query_numeric_type); 00414 00415 obj_val = 00416 ((query_numeric_getter) getter->param_getfcn) (object, getter); 00417