Query: Querying for Objects
[Query Object Framework]


Detailed Description

BASIC QUERY API: With this API you can create arbitrary logical queries to find sets of arbitrary object. To make simple queries (1 term, such as a search for a parameter with one value), create the appropriate QueryTerm structure and stick it in a Query object using xaccInitQuery. The QueryTerm should be malloced but the Query object will handle freeing it. To make compound queries, make multiple simple queries and combine them using qof_query_merge() and the logical operations of your choice.

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,...)
QofQueryqof_query_create (void)
QofQueryqof_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)
QofQueryqof_query_copy (QofQuery *q)
QofQueryqof_query_invert (QofQuery *q)
QofQueryqof_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

QofQueryPredDataqof_query_string_predicate (QofQueryCompare how, const gchar *str, QofStringMatch options, gboolean is_regex)
QofQueryPredDataqof_query_time_predicate (QofQueryCompare how, QofDateMatch options, QofTime *qt)
QofQueryPredDataqof_query_numeric_predicate (QofQueryCompare how, QofNumericMatch options, QofNumeric value)
QofQueryPredDataqof_query_guid_predicate (QofGuidMatch options, GList *guids)
QofQueryPredDataqof_query_int32_predicate (QofQueryCompare how, gint32 val)
QofQueryPredDataqof_query_int64_predicate (QofQueryCompare how, gint64 val)
QofQueryPredDataqof_query_double_predicate (QofQueryCompare how, double val)
QofQueryPredDataqof_query_boolean_predicate (QofQueryCompare how, gboolean val)
QofQueryPredDataqof_query_char_predicate (QofCharMatch options, const gchar *chars)
QofQueryPredDataqof_query_collect_predicate (QofGuidMatch options, QofCollection *coll)
QofQueryPredDataqof_query_choice_predicate (QofGuidMatch options, GList *guids)
QofQueryPredDataqof_query_kvp_predicate (QofQueryCompare how, GSList *path, const KvpValue *value)
QofQueryPredDataqof_query_kvp_predicate_path (QofQueryCompare how, const gchar *path, const KvpValue *value)
QofQueryPredDataqof_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 Documentation

#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 Documentation

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.


Enumeration Type Documentation

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

Enumerator:
QOF_GUID_MATCH_ANY  These expect a single object and expect the QofAccessFunc returns GUID*
QOF_GUID_MATCH_ALL  These expect a GList* of objects and calls the QofAccessFunc routine on each item in the list to obtain a GUID* for each object
QOF_GUID_MATCH_LIST_ANY  These expect a single object and expect the QofAccessFunc function to return a GList* of GUID* (the list is the property of the caller)

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;


Function Documentation

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);

Note:
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 You can simulate a join by using recursive or sequential queries.

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 }

QofQuery* qof_query_copy ( QofQuery q  ) 

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.

gchar* qof_query_core_to_string ( QofType  ,
gpointer  object,
QofParam getter 
)

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 }

gboolean qof_query_equal ( QofQuery q1,
QofQuery q2 
)

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  ) 

Return the list of books we're using

Definition at line 1352 of file qofquery.c.

01353 {
01354     if (!q)
01355         return NULL;
01356     return q->books;
01357 }

QofIdType qof_query_get_search_for ( QofQuery q  ) 

Return the type of data we're querying for

Definition at line 1400 of file qofquery.c.

01401 {
01402     if (!q)
01403         return NULL;
01404     return q->search_for;
01405 }

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.

00934 {
00935     if (!q)
00936         return 0;
00937     return g_list_length (q->terms);
00938 }

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 }

QofQuery* qof_query_invert ( QofQuery q  ) 

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.

00878 {
00879     if (!query)
00880         return NULL;
00881 
00882     return query->results;
00883 }

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 }

void qof_query_set_book ( QofQuery q,
QofBook book 
)

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.

01294 {
01295     if (!q)
01296         return;
01297     q->max_results = n;
01298 }

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 


Generated on Thu Jan 31 22:50:27 2008 for QOF by  doxygen 1.5.4