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 funtion. The PredicateData structure is a constant associated with the Term and is identical for every object that is tested.

The terms of the Query may represent any logical function and are stored in canonical form, i.e. the function is expressed as a logical sum of logical products. So if you have QueryTerms a, b, c, d, e and you have the logical function a(b+c) + !(c(d+e)), it gets stored as ab + ac + !c + !c!e +!d!c + !d!e. This may not be optimal for evaluation of some functions but it's easy to store, easy to manipulate, and it doesn't require a complete algebra system to deal with.

The representation is of a GList of GLists of QueryTerms. The "backbone" GList q->terms represents the OR-chain, and every item on the backbone is a GList of QueryTerms representing an AND-chain corresponding to a single product-term in the canonical representation. QueryTerms are duplicated when necessary to fill out the canonical form, and the same predicate may be evaluated multiple times per split for complex queries. This is a place where we could probably optimize.


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 (char 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)
GList * qof_query_run_subquery (QofQuery *subquery, const QofQuery *primary_query)
void qof_query_clear (QofQuery *query)
void qof_query_purge_terms (QofQuery *q, GSList *param_list)
int qof_query_has_terms (QofQuery *q)
int 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, int n)
gboolean qof_query_equal (const QofQuery *q1, const QofQuery *q2)
void qof_query_print (QofQuery *query)
QofIdType qof_query_get_search_for (const 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_date_predicate (QofQueryCompare how, QofDateMatch options, Timespec date)
QofQueryPredDataqof_query_numeric_predicate (QofQueryCompare how, QofNumericMatch options, gnc_numeric 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 (const QofQueryPredData *pdata)
void qof_query_core_predicate_free (QofQueryPredData *pdata)
gboolean qof_query_date_predicate_get_date (const QofQueryPredData *pd, Timespec *date)
char * qof_query_core_to_string (QofType, gpointer object, QofParam *getter)
int qof_string_number_compare_func (gpointer a, gpointer b, gint options, QofParam *this_param)

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 Documentation

#define QOF_PARAM_BOOK   "book"

"Known" Object Parameters -- all objects must support these

Definition at line 103 of file qofquery.h.

#define QOF_PARAM_KVP   "kvp"

"Known" Object Parameters -- some objects might support these

Definition at line 107 of file qofquery.h.

#define QOF_QUERY_FIRST_TERM   QOF_QUERY_AND

First/only term is same as 'and'

Definition at line 97 of file qofquery.h.

#define QUERY_DEFAULT_SORT   "QofQueryDefaultSort"

Default sort object type

Definition at line 100 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 45 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.

Enumerator:
QOF_CHAR_MATCH_ANY 
QOF_CHAR_MATCH_NONE 

Definition at line 121 of file qofquerycore.h.

00121              {
00122   QOF_CHAR_MATCH_ANY = 1,
00123   QOF_CHAR_MATCH_NONE
00124 } 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.

Enumerator:
QOF_DATE_MATCH_NORMAL 
QOF_DATE_MATCH_DAY 

Definition at line 75 of file qofquerycore.h.

00075              {
00076   QOF_DATE_MATCH_NORMAL = 1,
00077   QOF_DATE_MATCH_DAY
00078 } QofDateMatch;

enum QofGuidMatch

Enumerator:
QOF_GUID_MATCH_ANY  These expect a single object and expect the QofAccessFunc returns GUID*
QOF_GUID_MATCH_NONE 
QOF_GUID_MATCH_NULL 
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 99 of file qofquerycore.h.

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)

Enumerator:
QOF_NUMERIC_MATCH_DEBIT 
QOF_NUMERIC_MATCH_CREDIT 
QOF_NUMERIC_MATCH_ANY 

Definition at line 92 of file qofquerycore.h.

enum QofQueryCompare

Standard Query comparitors, for how to compare objects in a predicate. Note that not all core types implement all comparitors

Enumerator:
QOF_COMPARE_LT 
QOF_COMPARE_LTE 
QOF_COMPARE_EQUAL 
QOF_COMPARE_GT 
QOF_COMPARE_GTE 
QOF_COMPARE_NEQ 

Definition at line 50 of file qofquerycore.h.

enum QofQueryOp

Query Term Operators, for combining Query Terms

Enumerator:
QOF_QUERY_AND 
QOF_QUERY_OR 
QOF_QUERY_NAND 
QOF_QUERY_NOR 
QOF_QUERY_XOR 

Definition at line 88 of file qofquery.h.

00088              {
00089   QOF_QUERY_AND=1,
00090   QOF_QUERY_OR,
00091   QOF_QUERY_NAND,
00092   QOF_QUERY_NOR,
00093   QOF_QUERY_XOR
00094 } QofQueryOp;

enum QofStringMatch

List of known core query data-types... Each core query type defines it's set of optional "comparitor qualifiers".

Enumerator:
QOF_STRING_MATCH_NORMAL 
QOF_STRING_MATCH_CASEINSENSITIVE 

Definition at line 63 of file qofquerycore.h.


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 1282 of file qofquery.c.

01284 {
01285   QofQueryPredData *pdata;
01286   if (!q || !param_list) return;
01287 
01288   pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value);
01289   qof_query_add_term (q, param_list, pdata, op);
01290 }

void qof_query_add_guid_list_match ( QofQuery q,
GSList *  param_list,
GList *  guid_list,
QofGuidMatch  options,
QofQueryOp  op 
)

DOCUMENT ME !!

Definition at line 1230 of file qofquery.c.

01233 {
01234   QofQueryPredData *pdata;
01235 
01236   if (!q || !param_list) return;
01237 
01238   if (!guid_list)
01239     g_return_if_fail (options == QOF_GUID_MATCH_NULL);
01240 
01241   pdata = qof_query_guid_predicate (options, guid_list);
01242   qof_query_add_term (q, param_list, pdata, op);
01243 }

void qof_query_add_guid_match ( QofQuery q,
GSList *  param_list,
const GUID guid,
QofQueryOp  op 
)

DOCUMENT ME !!

Definition at line 1245 of file qofquery.c.

01247 {
01248   GList *g = NULL;
01249 
01250   if (!q || !param_list) return;
01251 
01252   if (guid)
01253     g = g_list_prepend (g, (gpointer)guid);
01254 
01255   qof_query_add_guid_list_match (q, param_list, g,
01256                             g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op);
01257 
01258   g_list_free (g);
01259 }

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 comparitor.

The param_list is a recursive list of parameters. For example, you can say 'split->memo' by creating a list of one element, "SPLIT_MEMO". You can say 'split->account->name' by creating a list of two elements, "SPLIT_ACCOUNT" and "ACCOUNT_NAME". The list becomes the property of the Query.

For example:

acct_name_pred_data = make_string_pred_data(QOF_STRING_MATCH_CASEINSENSITIVE, account_name); param_list = make_list (SPLIT_ACCOUNT, ACCOUNT_NAME, NULL); qof_query_add_term (query, param_list, QOF_COMPARE_EQUAL, acct_name_pred_data, QOF_QUERY_AND);

Please note that QofQuery does not, at this time, support joins. That is, one cannot specify a predicate that is a parameter list. Put another way, one cannot search for objects where obja->thingy == objb->stuff

Definition at line 634 of file qofquery.c.

00636 {
00637   QofQueryTerm *qt;
00638   QofQuery *qr, *qs;
00639 
00640   if (!q || !param_list || !pred_data) return;
00641 
00642   qt = g_new0 (QofQueryTerm, 1);
00643   qt->param_list = param_list;
00644   qt->pdata = pred_data;
00645   qs = qof_query_create ();
00646   query_init (qs, qt);
00647 
00648   if (qof_query_has_terms (q))
00649     qr = qof_query_merge (q, qs, op);
00650   else
00651     qr = qof_query_merge (q, qs, QOF_QUERY_OR);
00652 
00653   swap_terms (q, qr);
00654   qof_query_destroy (qs);
00655   qof_query_destroy (qr);
00656 }

void qof_query_clear ( QofQuery query  ) 

Remove all query terms from query. query matches nothing after qof_query_clear().

Definition at line 850 of file qofquery.c.

00851 {
00852   QofQuery *q2 = qof_query_create ();
00853   swap_terms (query, q2);
00854   qof_query_destroy (q2);
00855 
00856   g_list_free (query->books);
00857   query->books = NULL;
00858   g_list_free (query->results);
00859   query->results = NULL;
00860   query->changed = 1;
00861 }

QofQuery* qof_query_copy ( QofQuery q  ) 

Make a copy of the indicated query

Definition at line 956 of file qofquery.c.

00957 {
00958   QofQuery *copy;
00959   GHashTable *ht;
00960 
00961   if (!q) return NULL;
00962   copy = qof_query_create ();
00963   ht = copy->be_compiled;
00964   free_members (copy);
00965 
00966   memcpy (copy, q, sizeof (QofQuery));
00967 
00968   copy->be_compiled = ht;
00969   copy->terms = copy_or_terms (q->terms);
00970   copy->books = g_list_copy (q->books);
00971   copy->results = g_list_copy (q->results);
00972 
00973   copy_sort (&(copy->primary_sort), &(q->primary_sort));
00974   copy_sort (&(copy->secondary_sort), &(q->secondary_sort));
00975   copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort));
00976 
00977   copy->changed = 1;
00978 
00979   return copy;
00980 }

QofQueryPredData* qof_query_core_predicate_copy ( const QofQueryPredData pdata  ) 

Copy a predicate.

Definition at line 1822 of file qofquerycore.c.

01823 {
01824   QueryPredicateCopyFunc copy;
01825 
01826   g_return_val_if_fail (pdata, NULL);
01827   g_return_val_if_fail (pdata->type_name, NULL);
01828 
01829   copy = qof_query_copy_predicate (pdata->type_name);
01830   return (copy (pdata));
01831 }

void qof_query_core_predicate_free ( QofQueryPredData pdata  ) 

Destroy a predicate.

Definition at line 1810 of file qofquerycore.c.

01811 {
01812   QueryPredDataFree free_fcn;
01813 
01814   g_return_if_fail (pdata);
01815   g_return_if_fail (pdata->type_name);
01816 
01817   free_fcn = qof_query_predicate_free (pdata->type_name);
01818   free_fcn (pdata);
01819 }

char* 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 1834 of file qofquerycore.c.

01836 {
01837   QueryToString toString;
01838 
01839   g_return_val_if_fail (type, NULL);
01840   g_return_val_if_fail (object, NULL);
01841   g_return_val_if_fail (getter, NULL);
01842 
01843   toString = g_hash_table_lookup (toStringTable, type);
01844   g_return_val_if_fail (toString, NULL);
01845 
01846   return toString (object, getter);
01847 }

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 863 of file qofquery.c.

00864 {
00865   QofQuery *qp = g_new0 (QofQuery, 1);
00866   qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal);
00867   query_init (qp, NULL);
00868   return qp;
00869 }

gboolean qof_query_date_predicate_get_date ( const QofQueryPredData pd,
Timespec date 
)

Retrieve a predicate.

Definition at line 412 of file qofquerycore.c.

00413 {
00414   const query_date_t pdata = (const query_date_t)pd;
00415 
00416   if (pdata->pd.type_name != query_date_type)
00417     return FALSE;
00418   *date = pdata->date;
00419   return TRUE;
00420 }

void qof_query_destroy ( QofQuery q  ) 

Frees the resources associate with a Query object.

Definition at line 947 of file qofquery.c.

00948 {
00949   if (!q) return;
00950   free_members (q);
00951   query_clear_compiles (q);
00952   g_hash_table_destroy (q->be_compiled);
00953   g_free (q);
00954 }

gboolean qof_query_equal ( const QofQuery q1,
const 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 1407 of file qofquery.c.

01408 {
01409   GList *or1, *or2;
01410 
01411   if (q1 == q2) return TRUE;
01412   if (!q1 || !q2) return FALSE;
01413 
01414   if (g_list_length (q1->terms) != g_list_length (q2->terms)) return FALSE;
01415   if (q1->max_results != q2->max_results) return FALSE;
01416 
01417   for (or1 = q1->terms, or2 = q2->terms; or1;
01418        or1 = or1->next, or2 = or2->next)
01419   {
01420     GList *and1, *and2;
01421 
01422     and1 = or1->data;
01423     and2 = or2->data;
01424 
01425     if (g_list_length (and1) != g_list_length (and2)) return FALSE;
01426 
01427     for ( ; and1; and1 = and1->next, and2 = and2->next)
01428       if (!qof_query_term_equal (and1->data, and2->data))
01429         return FALSE;
01430   }
01431 
01432   if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort)))
01433     return FALSE;
01434   if (!qof_query_sort_equal (&(q1->secondary_sort), &(q2->secondary_sort)))
01435     return FALSE;
01436   if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort)))
01437     return FALSE;
01438 
01439   return TRUE;
01440 }

GList* qof_query_get_books ( QofQuery q  ) 

Return the list of books we're using

Definition at line 1276 of file qofquery.c.

01277 {
01278   if (!q) return NULL;
01279   return q->books;
01280 }

QofIdType qof_query_get_search_for ( const QofQuery q  ) 

Return the type of data we're querying for

Definition at line 1315 of file qofquery.c.

01316 {
01317   if (!q) return NULL;
01318   return q->search_for;
01319 }

gboolean qof_query_has_term_type ( QofQuery q,
GSList *  term_param 
)

DOCUMENT ME !!

Definition at line 908 of file qofquery.c.

00909 {
00910   GList *or;
00911   GList *and;
00912 
00913   if (!q || !term_param)
00914     return FALSE;
00915 
00916   for(or = q->terms; or; or = or->next) {
00917     for(and = or->data; and; and = and->next) {
00918       QofQueryTerm *qt = and->data;
00919       if (!param_list_cmp (term_param, qt->param_list))
00920         return TRUE;
00921     }
00922   }
00923 
00924   return FALSE;
00925 }

int 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 892 of file qofquery.c.

00893 {
00894   if (!q) return 0;
00895   return g_list_length (q->terms);
00896 }

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 1295 of file qofquery.c.

01296 {
01297   ENTER (" ");
01298   qof_query_core_init ();
01299   qof_class_init ();
01300   LEAVE ("Completed initialization of QofQuery");
01301 }

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 988 of file qofquery.c.

00989 {
00990   QofQuery  * retval;
00991   QofQuery  * right, * left, * iright, * ileft;
00992   QofQueryTerm * qt;
00993   GList  * aterms;
00994   GList  * cur;
00995   GList  * new_oterm;
00996   int    num_or_terms;
00997 
00998   if (!q)
00999     return NULL;
01000 
01001   num_or_terms = g_list_length(q->terms);
01002 
01003   switch(num_or_terms) 
01004   {
01005   case 0:
01006     retval = qof_query_create();
01007     retval->max_results = q->max_results;
01008     break;
01009 
01010     /* This is the DeMorgan expansion for a single AND expression. */
01011     /* !(abc) = !a + !b + !c */
01012   case 1:
01013     retval = qof_query_create();
01014     retval->max_results = q->max_results;
01015     retval->books = g_list_copy (q->books);
01016     retval->search_for = q->search_for;
01017     retval->changed = 1;
01018 
01019     aterms = g_list_nth_data(q->terms, 0);
01020     new_oterm = NULL;
01021     for(cur=aterms; cur; cur=cur->next) {
01022       qt = copy_query_term(cur->data);
01023       qt->invert = !(qt->invert);
01024       new_oterm = g_list_append(NULL, qt);
01025       retval->terms = g_list_prepend(retval->terms, new_oterm);
01026     }
01027     retval->terms = g_list_reverse(retval->terms);
01028     break;
01029 
01030     /* If there are multiple OR-terms, we just recurse by 
01031      * breaking it down to !(a + b + c) = 
01032      * !a * !(b + c) = !a * !b * !c.  */
01033   default:
01034     right        = qof_query_create();
01035     right->terms = copy_or_terms(g_list_nth(q->terms, 1));
01036 
01037     left         = qof_query_create();
01038     left->terms  = g_list_append(NULL, 
01039                                  copy_and_terms(g_list_nth_data(q->terms, 0)));
01040 
01041     iright       = qof_query_invert(right);
01042     ileft        = qof_query_invert(left);
01043 
01044     retval = qof_query_merge(iright, ileft, QOF_QUERY_AND);
01045     retval->books          = g_list_copy (q->books);
01046     retval->max_results    = q->max_results;
01047     retval->search_for     = q->search_for;
01048     retval->changed        = 1;
01049 
01050     qof_query_destroy(iright);
01051     qof_query_destroy(ileft);
01052     qof_query_destroy(right);
01053     qof_query_destroy(left);
01054     break;
01055   }
01056 
01057   return retval;
01058 }

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 1268 of file qofquerycore.c.

01270 {
01271   query_kvp_t pdata;
01272   GSList *node;
01273 
01274   g_return_val_if_fail (path && value, NULL);
01275 
01276   pdata = g_new0 (query_kvp_def, 1);
01277   pdata->pd.type_name = query_kvp_type;
01278   pdata->pd.how = how;
01279   pdata->value = kvp_value_copy (value);
01280   pdata->path = g_slist_copy (path);
01281   for (node = pdata->path; node; node = node->next)
01282     node->data = g_strdup (node->data);
01283 
01284   return ((QofQueryPredData*)pdata);
01285 }

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 842 of file qofquery.c.

00843 {
00844   if (!query)
00845     return NULL;
00846 
00847   return query->results;
00848 }

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. Note that if either input query is NULL then the returned query is NOT newly allocated -- it will return the non-NULL query. You only need to call this function when both q1 and q2 are non-NULL.

Definition at line 1066 of file qofquery.c.

01067 {
01068   
01069   QofQuery * retval = NULL;
01070   QofQuery * i1, * i2;
01071   QofQuery * t1, * t2;
01072   GList * i, * j;
01073   QofIdType search_for;
01074 
01075   if(!q1) return q2;
01076   if(!q2) return q1;
01077 
01078   if (q1->search_for && q2->search_for)
01079     g_return_val_if_fail (safe_strcmp (q1->search_for, q2->search_for) == 0,
01080                           NULL);
01081 
01082   search_for = (q1->search_for ? q1->search_for : q2->search_for);
01083 
01084   /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty.
01085    * The goal of this tweak is to all the user to start with
01086    * an empty q1 and then append to it recursively
01087    * (and q1 (and q2 (and q3 (and q4 ....))))
01088    * without bombing out because the append started with an 
01089    * empty list.
01090    * We do essentially the same check in qof_query_add_term()
01091    * so that the first term added to an empty query doesn't screw up.
01092    */
01093   if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1)))
01094   {
01095     op = QOF_QUERY_OR;
01096   }
01097 
01098   switch(op) 
01099   {
01100   case QOF_QUERY_OR:
01101     retval = qof_query_create();
01102     retval->terms = 
01103       g_list_concat(copy_or_terms(q1->terms), copy_or_terms(q2->terms));
01104     retval->books           = merge_books (q1->books, q2->books);
01105     retval->max_results    = q1->max_results;
01106     retval->changed        = 1;
01107     break;
01108 
01109   case QOF_QUERY_AND:
01110     retval = qof_query_create();
01111     retval->books          = merge_books (q1->books, q2->books);
01112     retval->max_results    = q1->max_results;
01113     retval->changed        = 1;
01114 
01115     /* g_list_append() can take forever, so let's build the list in
01116      * reverse and then reverse it at the end, to deal better with
01117      * "large" queries.
01118      */
01119     for(i=q1->terms; i; i=i->next) 
01120     {
01121       for(j=q2->terms; j; j=j->next) 
01122       {
01123         retval->terms = 
01124           g_list_prepend(retval->terms, 
01125                         g_list_concat
01126                         (copy_and_terms(i->data),
01127                          copy_and_terms(j->data)));
01128       }
01129     }
01130     retval->terms = g_list_reverse(retval->terms);
01131     break;
01132 
01133   case QOF_QUERY_NAND:
01134     /* !(a*b) = (!a + !b) */
01135     i1     = qof_query_invert(q1);
01136     i2     = qof_query_invert(q2);
01137     retval = qof_query_merge(i1, i2, QOF_QUERY_OR);
01138     qof_query_destroy(i1);
01139     qof_query_destroy(i2);
01140     break;
01141 
01142   case QOF_QUERY_NOR:
01143     /* !(a+b) = (!a*!b) */
01144     i1     =