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, QofNumeric 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 struct _QofQuery | QofQuery |
typedef struct _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 1360 of file qofquery.c.
01362 { 01363 QofQueryPredData *pdata; 01364 if (!q || !param_list) 01365 return; 01366 01367 pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value); 01368 qof_query_add_term (q, param_list, pdata, op); 01369 }
void qof_query_add_guid_list_match | ( | QofQuery * | q, | |
GSList * | param_list, | |||
GList * | guid_list, | |||
QofGuidMatch | options, | |||
QofQueryOp | op | |||
) |
DOCUMENT ME !!
Definition at line 1301 of file qofquery.c.
01303 { 01304 QofQueryPredData *pdata; 01305 01306 if (!q || !param_list) 01307 return; 01308 01309 if (!guid_list) 01310 g_return_if_fail (options == QOF_GUID_MATCH_NULL); 01311 01312 pdata = qof_query_guid_predicate (options, guid_list); 01313 qof_query_add_term (q, param_list, pdata, op); 01314 }
void qof_query_add_guid_match | ( | QofQuery * | q, | |
GSList * | param_list, | |||
const GUID * | guid, | |||
QofQueryOp | op | |||
) |
DOCUMENT ME !!
Definition at line 1317 of file qofquery.c.
01319 { 01320 GList *g = NULL; 01321 01322 if (!q || !param_list) 01323 return; 01324 01325 if (guid) 01326 g = g_list_prepend (g, (gpointer) guid); 01327 01328 qof_query_add_guid_list_match (q, param_list, g, 01329 g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op); 01330 01331 g_list_free (g); 01332 }
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 691 of file qofquery.c.
00693 { 00694 QofQueryTerm *qt; 00695 QofQuery *qr, *qs; 00696 00697 if (!q || !param_list || !pred_data) 00698 return; 00699 00700 qt = g_new0 (QofQueryTerm, 1); 00701 qt->param_list = param_list; 00702 qt->pdata = pred_data; 00703 qs = qof_query_create (); 00704 query_init (qs, qt); 00705 00706 if (qof_query_has_terms (q)) 00707 qr = qof_query_merge (q, qs, op); 00708 else 00709 qr = qof_query_merge (q, qs, QOF_QUERY_OR); 00710 00711 swap_terms (q, qr); 00712 qof_query_destroy (qs); 00713 qof_query_destroy (qr); 00714 }
void qof_query_clear | ( | QofQuery * | query | ) |
Remove all query terms from query. query matches nothing after qof_query_clear().
Definition at line 886 of file qofquery.c.
00887 { 00888 QofQuery *q2 = qof_query_create (); 00889 swap_terms (query, q2); 00890 qof_query_destroy (q2); 00891 00892 g_list_free (query->books); 00893 query->books = NULL; 00894 g_list_free (query->results); 00895 query->results = NULL; 00896 query->changed = 1; 00897 }
Make a copy of the indicated query
Definition at line 1009 of file qofquery.c.
01010 { 01011 QofQuery *copy; 01012 GHashTable *ht; 01013 01014 if (!q) 01015 return NULL; 01016 copy = qof_query_create (); 01017 ht = copy->be_compiled; 01018 free_members (copy); 01019 01020 memcpy (copy, q, sizeof (QofQuery)); 01021 01022 copy->be_compiled = ht; 01023 copy->terms = copy_or_terms (q->terms); 01024 copy->books = g_list_copy (q->books); 01025 copy->results = g_list_copy (q->results); 01026 01027 copy_sort (&(copy->primary_sort), &(q->primary_sort)); 01028 copy_sort (&(copy->secondary_sort), &(q->secondary_sort)); 01029 copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort)); 01030 01031 copy->changed = 1; 01032 01033 return copy; 01034 }
QofQueryPredData* qof_query_core_predicate_copy | ( | QofQueryPredData * | pdata | ) |
Copy a predicate.
Definition at line 2108 of file qofquerycore.c.
void qof_query_core_predicate_free | ( | QofQueryPredData * | pdata | ) |
Destroy a predicate.
Definition at line 2096 of file qofquerycore.c.
Return a printable string for a core data object. Caller needs to g_free() the returned string.
Definition at line 2120 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 900 of file qofquery.c.
00901 { 00902 QofQuery *qp = g_new0 (QofQuery, 1); 00903 qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal); 00904 query_init (qp, NULL); 00905 return qp; 00906 }
QofQuery* qof_query_create_for | ( | QofIdTypeConst | obj_type | ) |
create a query with a search type preset.
Definition at line 922 of file qofquery.c.
00923 { 00924 QofQuery *q; 00925 if (!obj_type) 00926 return NULL; 00927 q = qof_query_create (); 00928 qof_query_search_for (q, obj_type); 00929 return q; 00930 }
void qof_query_destroy | ( | QofQuery * | q | ) |
Frees the resources associated with a Query object.
Definition at line 998 of file qofquery.c.
00999 { 01000 if (!q) 01001 return; 01002 free_members (q); 01003 query_clear_compiles (q); 01004 g_hash_table_destroy (q->be_compiled); 01005 g_free (q); 01006 }
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 1512 of file qofquery.c.
01513 { 01514 GList *or1, *or2; 01515 01516 if (q1 == q2) 01517 return TRUE; 01518 if (!q1 || !q2) 01519 return FALSE; 01520 01521 if (g_list_length (q1->terms) != g_list_length (q2->terms)) 01522 return FALSE; 01523 if (q1->max_results != q2->max_results) 01524 return FALSE; 01525 01526 for (or1 = q1->terms, or2 = q2->terms; or1; 01527 or1 = or1->next, or2 = or2->next) 01528 { 01529 GList *and1, *and2; 01530 01531 and1 = or1->data; 01532 and2 = or2->data; 01533 01534 if (g_list_length (and1) != g_list_length (and2)) 01535 return FALSE; 01536 01537 for (; and1; and1 = and1->next, and2 = and2->next) 01538 if (!qof_query_term_equal (and1->data, and2->data)) 01539 return FALSE; 01540 } 01541 01542 if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort))) 01543 return FALSE; 01544 if (!qof_query_sort_equal (&(q1->secondary_sort), 01545 &(q2->secondary_sort))) 01546 return FALSE; 01547 if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort))) 01548 return FALSE; 01549 01550 return TRUE; 01551 }
GList* qof_query_get_books | ( | QofQuery * | q | ) |
gboolean qof_query_has_term_type | ( | QofQuery * | q, | |
GSList * | term_param | |||
) |
DOCUMENT ME !!
Definition at line 953 of file qofquery.c.
00954 { 00955 GList *or; 00956 GList *and; 00957 00958 if (!q || !term_param) 00959 return FALSE; 00960 00961 for (or = q->terms; or; or = or->next) 00962 { 00963 for (and = or->data; and; and = and->next) 00964 { 00965 QofQueryTerm *qt = and->data; 00966 if (!param_list_cmp (term_param, qt->param_list)) 00967 return TRUE; 00968 } 00969 } 00970 00971 return FALSE; 00972 }
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 933 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 1375 of file qofquery.c.
01376 { 01377 ENTER (" "); 01378 qof_query_core_init (); 01379 qof_class_init (); 01380 qof_date_init (); 01381 LEAVE ("Completed initialization of QofQuery"); 01382 }
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 1043 of file qofquery.c.
01044 { 01045 QofQuery *retval; 01046 QofQuery *right, *left, *iright, *ileft; 01047 QofQueryTerm *qt; 01048 GList *aterms; 01049 GList *cur; 01050 GList *new_oterm; 01051 gint num_or_terms; 01052 01053 if (!q) 01054 return NULL; 01055 01056 num_or_terms = g_list_length (q->terms); 01057 01058 switch (num_or_terms) 01059 { 01060 case 0: 01061 retval = qof_query_create (); 01062 retval->max_results = q->max_results; 01063 break; 01064 01065 /* This is the DeMorgan expansion for a single AND expression. */ 01066 /* !(abc) = !a + !b + !c */ 01067 case 1: 01068 retval = qof_query_create (); 01069 retval->max_results = q->max_results; 01070 retval->books = g_list_copy (q->books); 01071 retval->search_for = q->search_for; 01072 retval->changed = 1; 01073 01074 aterms = g_list_nth_data (q->terms, 0); 01075 new_oterm = NULL; 01076 for (cur = aterms; cur; cur = cur->next) 01077 { 01078 qt = copy_query_term (cur->data); 01079 qt->invert = !(qt->invert); 01080 new_oterm = g_list_append (NULL, qt); 01081 01082 /* g_list_append() can take forever, so let's do this for speed 01083 * in "large" queries. 01084 */ 01085 retval->terms = g_list_reverse (retval->terms); 01086 retval->terms = g_list_prepend (retval->terms, new_oterm); 01087 retval->terms = g_list_reverse (retval->terms); 01088 } 01089 break; 01090 01091 /* If there are multiple OR-terms, we just recurse by 01092 * breaking it down to !(a + b + c) = 01093 * !a * !(b + c) = !a * !b * !c. */ 01094 default: 01095 right = qof_query_create (); 01096 right->terms = copy_or_terms (g_list_nth (q->terms, 1)); 01097 01098 left = qof_query_create (); 01099 left->terms = g_list_append (NULL, 01100 copy_and_terms (g_list_nth_data (q->terms, 0))); 01101 01102 iright = qof_query_invert (right); 01103 ileft = qof_query_invert (left); 01104 01105 retval = qof_query_merge (iright, ileft, QOF_QUERY_AND); 01106 retval->books = g_list_copy (q->books); 01107 retval->max_results = q->max_results; 01108 retval->search_for = q->search_for; 01109 retval->changed = 1; 01110 01111 qof_query_destroy (iright); 01112 qof_query_destroy (ileft); 01113 qof_query_destroy (right); 01114 qof_query_destroy (left); 01115 break; 01116 } 01117 01118 return retval; 01119 }
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 1312 of file qofquerycore.c.
01323 { 01324 spath = g_slist_append (spath, p); 01325 p = strchr (p, '/'); 01326 if (p) 01327 { 01328 *p = 0; 01329 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 877 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 1127 of file qofquery.c.
01128 { 01129 01130 QofQuery *retval = NULL; 01131 QofQuery *i1, *i2; 01132 QofQuery *t1, *t2; 01133 GList *i, *j; 01134 QofIdType search_for; 01135 01136 if (!q1) 01137 return q2; 01138 if (!q2) 01139 return q1; 01140 01141 if (q1->search_for && q2->search_for) 01142 g_return_val_if_fail (safe_strcmp (q1->search_for, 01143 q2->search_for) == 0, NULL); 01144 01145 search_for = (q1->search_for ? q1->search_for : q2->search_for); 01146 01147 /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty. 01148 * The goal of this tweak is to all the user to start with 01149 * an empty q1 and then append to it recursively 01150 * (and q1 (and q2 (and q3 (and q4 ....)))) 01151 * without bombing out because the append started with an 01152 * empty list. 01153 * We do essentially the same check in qof_query_add_term() 01154 * so that the first term added to an empty query doesn't screw up. 01155 */ 01156 if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1))) 01157 { 01158 op = QOF_QUERY_OR; 01159 } 01160 01161 switch (op) 01162 { 01163 case QOF_QUERY_OR: 01164 retval = qof_query_create (); 01165 retval->terms = 01166 g_list_concat (copy_or_terms (q1->terms), 01167 copy_or_terms (q2->terms)); 01168 retval->books = merge_books (q1->books, q2->books); 01169 retval->max_results = q1->max_results; 01170 retval->changed = 1; 01171 break; 01172 01173 case QOF_QUERY_AND: 01174 retval = qof_query_create (); 01175 retval->books = merge_books (q1->books, q2->books); 01176 retval->max_results = q1->max_results; 01177 retval->changed = 1; 01178 01179 /* g_list_append() can take forever, so let's build the list in 01180 * reverse and then reverse it at the end, to deal better with 01181 * "large" queries. 01182 */ 01183 for (i = q1->terms; i; i = i->next) 01184 { 01185 for (j = q2->terms; j; j = j->next) 01186 { 01187 retval->terms = 01188 g_list_prepend (retval->terms, 01189 g_list_concat 01190 (copy_and_terms (i->data), copy_and_terms (j->data))); 01191 } 01192 } 01193 retval->terms = g_list_reverse (retval->terms); 01194 break; 01195 01196 case QOF_QUERY_NAND: 01197 /* !(a*b) = (!a + !b) */ 01198 i1 = qof_query_invert (q1); 01199 i2 = qof_query_invert (q2); 01200 retval = qof_query_merge (i1, i2, QOF_QUERY_OR); 01201 qof_query_destroy (i1); 01202 qof_query_destroy (i2); 01203 break; 01204 01205 case QOF_QUERY_NOR: 01206 /* !(a+b) = (!a*!b) */ 01207 i1 = qof_query_invert (q1); 01208 i2 = qof_query_invert (q2); 01209 retval = qof_query_merge (i1, i2, QOF_QUERY_AND); 01210 qof_query_destroy (i1); 01211 qof_query_destroy (i2); 01212 break; 01213 01214 case QOF_QUERY_XOR: 01215 /* a xor b = (a * !b) + (!a * b) */ 01216 i1 = qof_query_invert (q1); 01217 i2 = qof_query_invert (q2); 01218 t1 = qof_query_merge (q1, i2, QOF_QUERY_AND); 01219 t2 = qof_query_merge (i1, q2, QOF_QUERY_AND); 01220 retval = qof_query_merge (t1, t2, QOF_QUERY_OR); 01221 01222 qof_query_destroy (i1); 01223 qof_query_destroy (i2); 01224 qof_query_destroy (t1); 01225 qof_query_destroy (t2); 01226 break; 01227 } 01228 01229 retval->search_for = search_for; 01230 return retval; 01231 }
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 1234 of file qofquery.c.
01235 { 01236 QofQuery *tmp_q; 01237 01238 if (!q1 || !q2) 01239 return; 01240 01241 tmp_q = qof_query_merge (q1, q2, op); 01242 swap_terms (q1, tmp_q); 01243 qof_query_destroy (tmp_q); 01244 }
gint qof_query_num_terms | ( | QofQuery * | q | ) |
Return the number of terms in the canonical form of the query.
Definition at line 941 of file qofquery.c.
00942 { 00943 GList *o; 00944 gint n = 0; 00945 if (!q) 00946 return 0; 00947 for (o = q->terms; o; o = o->next) 00948 n += g_list_length (o->data); 00949 return n; 00950 }
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 717 of file qofquery.c.
00718 { 00719 QofQueryTerm *qt; 00720 GList *or, *and; 00721 00722 if (!q || !param_list) 00723 return; 00724 00725 for (or = q->terms; or; or = or->next) 00726 { 00727 for (and = or->data; and; and = and->next) 00728 { 00729 qt = and->data; 00730 if (!param_list_cmp (qt->param_list, param_list)) 00731 { 00732 if (g_list_length (or->data) == 1) 00733 { 00734 q->terms = g_list_remove_link (q->terms, or); 00735 g_list_free_1 (or); 00736 or = q->terms; 00737 break; 00738 } 00739 else 00740 { 00741 or->data = g_list_remove_link (or->data, and); 00742 g_list_free_1 (and); 00743 and = or->data; 00744 if (!and) 00745 break; 00746 } 00747 q->changed = 1; 00748 free_query_term (qt); 00749 } 00750 } 00751 if (!or) 00752 break; 00753 } 00754 }
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 757 of file qofquery.c.
00758 { 00759 GList *matching_objects = NULL; 00760 GList *node; 00761 gint object_count = 0; 00762 00763 if (!q) 00764 return NULL; 00765 g_return_val_if_fail (q->search_for, NULL); 00766 g_return_val_if_fail (q->books, NULL); 00767 ENTER (" q=%p", q); 00768 00769 /* XXX: Prioritize the query terms? */ 00770 00771 /* prepare the Query for processing */ 00772 if (q->changed) 00773 { 00774 query_clear_compiles (q); 00775 compile_terms (q); 00776 } 00777 00778 /* Maybe log this sucker */ 00779 if (qof_log_check (log_module, QOF_LOG_DETAIL)) 00780 qof_query_print (q); 00781 00782 /* Now run the query over all the objects and save the results */ 00783 { 00784 QofQueryCB qcb; 00785 00786 memset (&qcb, 0, sizeof (qcb)); 00787 qcb.query = q; 00788 00789 /* For each book */ 00790 for (node = q->books; node; node = node->next) 00791 { 00792 QofBook *book = node->data; 00793 QofBackend *be = book->backend; 00794 00795 /* run the query in the backend */ 00796 if (be) 00797 { 00798 gpointer compiled_query = 00799 g_hash_table_lookup (q->be_compiled, book); 00800 00801 if (compiled_query && be->run_query) 00802 { 00803 (be->run_query) (be, compiled_query); 00804 } 00805 } 00806 00807 /* And then iterate over all the objects */ 00808 qof_object_foreach (q->search_for, book, 00809 (QofEntityForeachCB) check_item_cb, &qcb); 00810 } 00811 00812 matching_objects = qcb.list; 00813 object_count = qcb.count; 00814 } 00815 PINFO ("matching objects=%p count=%d", matching_objects, object_count); 00816 00817 /* There is no absolute need to reverse this list, since it's being 00818 * sorted below. However, in the common case, we will be searching 00819 * in a confined location where the objects are already in order, 00820 * thus reversing will put us in the correct order we want and make 00821 * the sorting go much faster. 00822 */ 00823 matching_objects = g_list_reverse (matching_objects); 00824 00825 /* Now sort the matching objects based on the search criteria 00826 * sortQuery is an unforgivable use of static global data... 00827 * I just can't figure out how else to do this sanely. 00828 */ 00829 if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp || 00830 (q->primary_sort.use_default && q->defaultSort)) 00831 { 00832 sortQuery = q; 00833 matching_objects = g_list_sort (matching_objects, sort_func); 00834 sortQuery = NULL; 00835 } 00836 00837 /* Crop the list to limit the number of splits. */ 00838 if ((object_count > q->max_results) && (q->max_results > -1)) 00839 { 00840 if (q->max_results > 0) 00841 { 00842 GList *mptr; 00843 00844 /* mptr is set to the first node of what will be the new list */ 00845 mptr = 00846 g_list_nth (matching_objects, 00847 object_count - q->max_results); 00848 /* mptr should not be NULL, but let's be safe */ 00849 if (mptr != NULL) 00850 { 00851 if (mptr->prev != NULL) 00852 mptr->prev->next = NULL; 00853 mptr->prev = NULL; 00854 } 00855 g_list_free (matching_objects); 00856 matching_objects = mptr; 00857 } 00858 else 00859 { 00860 /* q->max_results == 0 */ 00861 g_list_free (matching_objects); 00862 matching_objects = NULL; 00863 } 00864 object_count = q->max_results; 00865 } 00866 00867 q->changed = 0; 00868 00869 g_list_free (q->results); 00870 q->results = matching_objects; 00871 00872 LEAVE (" q=%p", q); 00873 return matching_objects; 00874 }
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 909 of file qofquery.c.
00910 { 00911 if (!q || !obj_type) 00912 return; 00913 00914 if (safe_strcmp (q->search_for, obj_type)) 00915 { 00916 q->search_for = (QofIdType) obj_type; 00917 q->changed = 1; 00918 } 00919 }
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 1335 of file qofquery.c.
01336 { 01337 GSList *slist = NULL; 01338 if (!q || !book) 01339 return; 01340 01341 /* Make sure this book is only in the list once */ 01342 if (g_list_index (q->books, book) == -1) 01343 q->books = g_list_prepend (q->books, book); 01344 01345 slist = g_slist_prepend (slist, QOF_PARAM_GUID); 01346 slist = g_slist_prepend (slist, QOF_PARAM_BOOK); 01347 qof_query_add_guid_match (q, slist, 01348 qof_entity_get_guid ((QofEntity*)book), QOF_QUERY_AND); 01349 }
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 1293 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 1282 of file qofquery.c.
01284 { 01285 if (!q) 01286 return; 01287 q->primary_sort.increasing = prim_inc; 01288 q->secondary_sort.increasing = sec_inc; 01289 q->tertiary_sort.increasing = tert_inc; 01290 }
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 1247 of file qofquery.c.
01249 { 01250 if (!q) 01251 return; 01252 if (q->primary_sort.param_list) 01253 g_slist_free (q->primary_sort.param_list); 01254 q->primary_sort.param_list = params1; 01255 q->primary_sort.options = 0; 01256 01257 if (q->secondary_sort.param_list) 01258 g_slist_free (q->secondary_sort.param_list); 01259 q->secondary_sort.param_list = params2; 01260 q->secondary_sort.options = 0; 01261 01262 if (q->tertiary_sort.param_list) 01263 g_slist_free (q->tertiary_sort.param_list); 01264 q->tertiary_sort.param_list = params3; 01265 q->tertiary_sort.options = 0; 01266 01267 q->changed = 1; 01268 }
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 QofNumeric obj_val; 00411 gint compare; 00412 00413 VERIFY_PREDICATE (query_numeric_type); 00414 00415 obj_val = 00416 ((query_numeric_getter) getter->param_getfcn) (object, getter); 00417