QOF  0.7.5
Query: Querying for Objects

Modules

 SQL Interface to Query
 

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.
 

Data Structures

struct  _QofQueryPredData
 

Macros

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

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)
 

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.

Macro Definition 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.

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

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.

128 {
129  QOF_CHAR_MATCH_ANY = 1,
130  QOF_CHAR_MATCH_NONE
131 } QofCharMatch;

Comparisons for QOF_TYPE_DATE The QOF_DATE_MATCH_DAY comparison rounds the two time values to mid-day and then compares these rounded values. The QOF_DATE_MATCH_NORMAL comparison matches the time values, down to the second.

Definition at line 78 of file qofquerycore.h.

79 {
80  QOF_DATE_MATCH_NORMAL = 1,
81  QOF_DATE_MATCH_DAY
82 } QofDateMatch;
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.

105 {
108  QOF_GUID_MATCH_ANY = 1,
109  QOF_GUID_MATCH_NONE,
110  QOF_GUID_MATCH_NULL,
117 } QofGuidMatch;

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.

97 {
98  QOF_NUMERIC_MATCH_DEBIT = 1,
99  QOF_NUMERIC_MATCH_CREDIT,
100  QOF_NUMERIC_MATCH_ANY

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.

52 {
53  QOF_COMPARE_LT = 1,
54  QOF_COMPARE_LTE,
55  QOF_COMPARE_EQUAL,
56  QOF_COMPARE_GT,
57  QOF_COMPARE_GTE,
58  QOF_COMPARE_NEQ
enum QofQueryOp

Query Term Operators, for combining Query Terms

Definition at line 88 of file qofquery.h.

89 {
90  QOF_QUERY_AND = 1,
91  QOF_QUERY_OR,
92  QOF_QUERY_NAND,
93  QOF_QUERY_NOR,
94  QOF_QUERY_XOR
95 } QofQueryOp;

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

Definition at line 65 of file qofquerycore.h.

66 {
67  QOF_STRING_MATCH_NORMAL = 1,
68  QOF_STRING_MATCH_CASEINSENSITIVE

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.

1362 {
1363  QofQueryPredData *pdata;
1364  if (!q || !param_list)
1365  return;
1366 
1367  pdata = qof_query_boolean_predicate (QOF_COMPARE_EQUAL, value);
1368  qof_query_add_term (q, param_list, pdata, op);
1369 }
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.

1303 {
1304  QofQueryPredData *pdata;
1305 
1306  if (!q || !param_list)
1307  return;
1308 
1309  if (!guid_list)
1310  g_return_if_fail (options == QOF_GUID_MATCH_NULL);
1311 
1312  pdata = qof_query_guid_predicate (options, guid_list);
1313  qof_query_add_term (q, param_list, pdata, op);
1314 }
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.

1319 {
1320  GList *g = NULL;
1321 
1322  if (!q || !param_list)
1323  return;
1324 
1325  if (guid)
1326  g = g_list_prepend (g, (gpointer) guid);
1327 
1328  qof_query_add_guid_list_match (q, param_list, g,
1329  g ? QOF_GUID_MATCH_ANY : QOF_GUID_MATCH_NULL, op);
1330 
1331  g_list_free (g);
1332 }
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.

693 {
694  QofQueryTerm *qt;
695  QofQuery *qr, *qs;
696 
697  if (!q || !param_list || !pred_data)
698  return;
699 
700  qt = g_new0 (QofQueryTerm, 1);
701  qt->param_list = param_list;
702  qt->pdata = pred_data;
703  qs = qof_query_create ();
704  query_init (qs, qt);
705 
706  if (qof_query_has_terms (q))
707  qr = qof_query_merge (q, qs, op);
708  else
709  qr = qof_query_merge (q, qs, QOF_QUERY_OR);
710 
711  swap_terms (q, qr);
712  qof_query_destroy (qs);
713  qof_query_destroy (qr);
714 }
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.

887 {
888  QofQuery *q2 = qof_query_create ();
889  swap_terms (query, q2);
890  qof_query_destroy (q2);
891 
892  g_list_free (query->books);
893  query->books = NULL;
894  g_list_free (query->results);
895  query->results = NULL;
896  query->changed = 1;
897 }
QofQuery* qof_query_copy ( QofQuery q)

Make a copy of the indicated query

Definition at line 1009 of file qofquery.c.

1010 {
1011  QofQuery *copy;
1012  GHashTable *ht;
1013 
1014  if (!q)
1015  return NULL;
1016  copy = qof_query_create ();
1017  ht = copy->be_compiled;
1018  free_members (copy);
1019 
1020  memcpy (copy, q, sizeof (QofQuery));
1021 
1022  copy->be_compiled = ht;
1023  copy->terms = copy_or_terms (q->terms);
1024  copy->books = g_list_copy (q->books);
1025  copy->results = g_list_copy (q->results);
1026 
1027  copy_sort (&(copy->primary_sort), &(q->primary_sort));
1028  copy_sort (&(copy->secondary_sort), &(q->secondary_sort));
1029  copy_sort (&(copy->tertiary_sort), &(q->tertiary_sort));
1030 
1031  copy->changed = 1;
1032 
1033  return copy;
1034 }
QofQueryPredData* qof_query_core_predicate_copy ( QofQueryPredData pdata)

Copy a predicate.

Definition at line 2054 of file qofquerycore.c.

2055 {
2056  QueryPredicateCopyFunc copy;
2057 
2058  g_return_val_if_fail (pdata, NULL);
2059  g_return_val_if_fail (pdata->type_name, NULL);
2060 
2061  copy = qof_query_copy_predicate (pdata->type_name);
2062  return (copy (pdata));
2063 }
void qof_query_core_predicate_free ( QofQueryPredData pdata)

Destroy a predicate.

Definition at line 2042 of file qofquerycore.c.

2043 {
2044  QueryPredDataFree free_fcn;
2045 
2046  g_return_if_fail (pdata);
2047  g_return_if_fail (pdata->type_name);
2048 
2049  free_fcn = qof_query_predicate_free (pdata->type_name);
2050  free_fcn (pdata);
2051 }
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 2066 of file qofquerycore.c.

2068 {
2069  QueryToString toString;
2070 
2071  g_return_val_if_fail (type, NULL);
2072  g_return_val_if_fail (object, NULL);
2073  g_return_val_if_fail (getter, NULL);
2074 
2075  toString = g_hash_table_lookup (toStringTable, type);
2076  g_return_val_if_fail (toString, NULL);
2077 
2078  return toString (object, getter);
2079 }
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.

901 {
902  QofQuery *qp = g_new0 (QofQuery, 1);
903  qp->be_compiled = g_hash_table_new (g_direct_hash, g_direct_equal);
904  query_init (qp, NULL);
905  return qp;
906 }
QofQuery* qof_query_create_for ( QofIdTypeConst  obj_type)

create a query with a search type preset.

Definition at line 922 of file qofquery.c.

923 {
924  QofQuery *q;
925  if (!obj_type)
926  return NULL;
927  q = qof_query_create ();
928  qof_query_search_for (q, obj_type);
929  return q;
930 }
void qof_query_destroy ( QofQuery q)

Frees the resources associated with a Query object.

Definition at line 998 of file qofquery.c.

999 {
1000  if (!q)
1001  return;
1002  free_members (q);
1003  query_clear_compiles (q);
1004  g_hash_table_destroy (q->be_compiled);
1005  g_free (q);
1006 }
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.

1513 {
1514  GList *or1, *or2;
1515 
1516  if (q1 == q2)
1517  return TRUE;
1518  if (!q1 || !q2)
1519  return FALSE;
1520 
1521  if (g_list_length (q1->terms) != g_list_length (q2->terms))
1522  return FALSE;
1523  if (q1->max_results != q2->max_results)
1524  return FALSE;
1525 
1526  for (or1 = q1->terms, or2 = q2->terms; or1;
1527  or1 = or1->next, or2 = or2->next)
1528  {
1529  GList *and1, *and2;
1530 
1531  and1 = or1->data;
1532  and2 = or2->data;
1533 
1534  if (g_list_length (and1) != g_list_length (and2))
1535  return FALSE;
1536 
1537  for (; and1; and1 = and1->next, and2 = and2->next)
1538  if (!qof_query_term_equal (and1->data, and2->data))
1539  return FALSE;
1540  }
1541 
1542  if (!qof_query_sort_equal (&(q1->primary_sort), &(q2->primary_sort)))
1543  return FALSE;
1544  if (!qof_query_sort_equal (&(q1->secondary_sort),
1545  &(q2->secondary_sort)))
1546  return FALSE;
1547  if (!qof_query_sort_equal (&(q1->tertiary_sort), &(q2->tertiary_sort)))
1548  return FALSE;
1549 
1550  return TRUE;
1551 }
GList* qof_query_get_books ( QofQuery q)

Return the list of books we're using

Definition at line 1352 of file qofquery.c.

1353 {
1354  if (!q)
1355  return NULL;
1356  return q->books;
1357 }
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.

1401 {
1402  if (!q)
1403  return NULL;
1404  return q->search_for;
1405 }
gboolean qof_query_has_term_type ( QofQuery q,
GSList *  term_param 
)

DOCUMENT ME !!

Definition at line 953 of file qofquery.c.

954 {
955  GList *or;
956  GList *and;
957 
958  if (!q || !term_param)
959  return FALSE;
960 
961  for (or = q->terms; or; or = or->next)
962  {
963  for (and = or->data; and; and = and->next)
964  {
965  QofQueryTerm *qt = and->data;
966  if (!param_list_cmp (term_param, qt->param_list))
967  return TRUE;
968  }
969  }
970 
971  return FALSE;
972 }
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.

934 {
935  if (!q)
936  return 0;
937  return g_list_length (q->terms);
938 }
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.

1376 {
1377  ENTER (" ");
1378  qof_query_core_init ();
1379  qof_class_init ();
1380  qof_date_init ();
1381  LEAVE ("Completed initialization of QofQuery");
1382 }
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.

1044 {
1045  QofQuery *retval;
1046  QofQuery *right, *left, *iright, *ileft;
1047  QofQueryTerm *qt;
1048  GList *aterms;
1049  GList *cur;
1050  GList *new_oterm;
1051  gint num_or_terms;
1052 
1053  if (!q)
1054  return NULL;
1055 
1056  num_or_terms = g_list_length (q->terms);
1057 
1058  switch (num_or_terms)
1059  {
1060  case 0:
1061  retval = qof_query_create ();
1062  retval->max_results = q->max_results;
1063  break;
1064 
1065  /* This is the DeMorgan expansion for a single AND expression. */
1066  /* !(abc) = !a + !b + !c */
1067  case 1:
1068  retval = qof_query_create ();
1069  retval->max_results = q->max_results;
1070  retval->books = g_list_copy (q->books);
1071  retval->search_for = q->search_for;
1072  retval->changed = 1;
1073 
1074  aterms = g_list_nth_data (q->terms, 0);
1075  new_oterm = NULL;
1076  for (cur = aterms; cur; cur = cur->next)
1077  {
1078  qt = copy_query_term (cur->data);
1079  qt->invert = !(qt->invert);
1080  new_oterm = g_list_append (NULL, qt);
1081 
1082  /* g_list_append() can take forever, so let's do this for speed
1083  * in "large" queries.
1084  */
1085  retval->terms = g_list_reverse (retval->terms);
1086  retval->terms = g_list_prepend (retval->terms, new_oterm);
1087  retval->terms = g_list_reverse (retval->terms);
1088  }
1089  break;
1090 
1091  /* If there are multiple OR-terms, we just recurse by
1092  * breaking it down to !(a + b + c) =
1093  * !a * !(b + c) = !a * !b * !c. */
1094  default:
1095  right = qof_query_create ();
1096  right->terms = copy_or_terms (g_list_nth (q->terms, 1));
1097 
1098  left = qof_query_create ();
1099  left->terms = g_list_append (NULL,
1100  copy_and_terms (g_list_nth_data (q->terms, 0)));
1101 
1102  iright = qof_query_invert (right);
1103  ileft = qof_query_invert (left);
1104 
1105  retval = qof_query_merge (iright, ileft, QOF_QUERY_AND);
1106  retval->books = g_list_copy (q->books);
1107  retval->max_results = q->max_results;
1108  retval->search_for = q->search_for;
1109  retval->changed = 1;
1110 
1111  qof_query_destroy (iright);
1112  qof_query_destroy (ileft);
1113  qof_query_destroy (right);
1114  qof_query_destroy (left);
1115  break;
1116  }
1117 
1118  return retval;
1119 }
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 1285 of file qofquerycore.c.

1287 {
1288  query_kvp_t pdata;
1289  GSList *node;
1290 
1291  g_return_val_if_fail (path && value, NULL);
1292 
1293  pdata = g_new0 (query_kvp_def, 1);
1294  pdata->pd.type_name = query_kvp_type;
1295  pdata->pd.how = how;
1296  pdata->value = kvp_value_copy (value);
1297  pdata->path = g_slist_copy (path);
1298  for (node = pdata->path; node; node = node->next)
1299  node->data = g_strdup (node->data);
1300 
1301  return ((QofQueryPredData *) pdata);
1302 }
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.

878 {
879  if (!query)
880  return NULL;
881 
882  return query->results;
883 }
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.

1128 {
1129 
1130  QofQuery *retval = NULL;
1131  QofQuery *i1, *i2;
1132  QofQuery *t1, *t2;
1133  GList *i, *j;
1134  QofIdType search_for;
1135 
1136  if (!q1)
1137  return q2;
1138  if (!q2)
1139  return q1;
1140 
1141  if (q1->search_for && q2->search_for)
1142  g_return_val_if_fail (safe_strcmp (q1->search_for,
1143  q2->search_for) == 0, NULL);
1144 
1145  search_for = (q1->search_for ? q1->search_for : q2->search_for);
1146 
1147  /* Avoid merge surprises if op==QOF_QUERY_AND but q1 is empty.
1148  * The goal of this tweak is to all the user to start with
1149  * an empty q1 and then append to it recursively
1150  * (and q1 (and q2 (and q3 (and q4 ....))))
1151  * without bombing out because the append started with an
1152  * empty list.
1153  * We do essentially the same check in qof_query_add_term()
1154  * so that the first term added to an empty query doesn't screw up.
1155  */
1156  if ((QOF_QUERY_AND == op) && (0 == qof_query_has_terms (q1)))
1157  {
1158  op = QOF_QUERY_OR;
1159  }
1160 
1161  switch (op)
1162  {
1163  case QOF_QUERY_OR:
1164  retval = qof_query_create ();
1165  retval->terms =
1166  g_list_concat (copy_or_terms (q1->terms),
1167  copy_or_terms (q2->terms));
1168  retval->books = merge_books (q1->books, q2->books);
1169  retval->max_results = q1->max_results;
1170  retval->changed = 1;
1171  break;
1172 
1173  case QOF_QUERY_AND:
1174  retval = qof_query_create ();
1175  retval->books = merge_books (q1->books, q2->books);
1176  retval->max_results = q1->max_results;
1177  retval->changed = 1;
1178 
1179  /* g_list_append() can take forever, so let's build the list in
1180  * reverse and then reverse it at the end, to deal better with
1181  * "large" queries.
1182  */
1183  for (i = q1->terms; i; i = i->next)
1184  {
1185  for (j = q2->terms; j; j = j->next)
1186  {
1187  retval->terms =
1188  g_list_prepend (retval->terms,
1189  g_list_concat
1190  (copy_and_terms (i->data), copy_and_terms (j->data)));
1191  }
1192  }
1193  retval->terms = g_list_reverse (retval->terms);
1194  break;
1195 
1196  case QOF_QUERY_NAND:
1197  /* !(a*b) = (!a + !b) */
1198  i1 = qof_query_invert (q1);
1199  i2 = qof_query_invert (q2);
1200  retval = qof_query_merge (i1, i2, QOF_QUERY_OR);
1201  qof_query_destroy (i1);
1202  qof_query_destroy (i2);
1203  break;
1204 
1205  case QOF_QUERY_NOR:
1206  /* !(a+b) = (!a*!b) */
1207  i1 = qof_query_invert (q1);
1208  i2 = qof_query_invert (q2);
1209  retval = qof_query_merge (i1, i2, QOF_QUERY_AND);
1210  qof_query_destroy (i1);
1211  qof_query_destroy (i2);
1212  break;
1213 
1214  case QOF_QUERY_XOR:
1215  /* a xor b = (a * !b) + (!a * b) */
1216  i1 = qof_query_invert (q1);
1217  i2 = qof_query_invert (q2);
1218  t1 = qof_query_merge (q1, i2, QOF_QUERY_AND);
1219  t2 = qof_query_merge (i1, q2, QOF_QUERY_AND);
1220  retval = qof_query_merge (t1, t2, QOF_QUERY_OR);
1221 
1222  qof_query_destroy (i1);
1223  qof_query_destroy (i2);
1224  qof_query_destroy (t1);
1225  qof_query_destroy (t2);
1226  break;
1227  }
1228 
1229  retval->search_for = search_for;
1230  return retval;
1231 }
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.

1235 {
1236  QofQuery *tmp_q;
1237 
1238  if (!q1 || !q2)
1239  return;
1240 
1241  tmp_q = qof_query_merge (q1, q2, op);
1242  swap_terms (q1, tmp_q);
1243  qof_query_destroy (tmp_q);
1244 }
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.

942 {
943  GList *o;
944  gint n = 0;
945  if (!q)
946  return 0;
947  for (o = q->terms; o; o = o->next)
948  n += g_list_length (o->data);
949  return n;
950 }
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.

718 {
719  QofQueryTerm *qt;
720  GList *or, *and;
721 
722  if (!q || !param_list)
723  return;
724 
725  for (or = q->terms; or; or = or->next)
726  {
727  for (and = or->data; and; and = and->next)
728  {
729  qt = and->data;
730  if (!param_list_cmp (qt->param_list, param_list))
731  {
732  if (g_list_length (or->data) == 1)
733  {
734  q->terms = g_list_remove_link (q->terms, or);
735  g_list_free_1 (or);
736  or = q->terms;
737  break;
738  }
739  else
740  {
741  or->data = g_list_remove_link (or->data, and);
742  g_list_free_1 (and);
743  and = or->data;
744  if (!and)
745  break;
746  }
747  q->changed = 1;
748  free_query_term (qt);
749  }
750  }
751  if (!or)
752  break;
753  }
754 }
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.

758 {
759  GList *matching_objects = NULL;
760  GList *node;
761  gint object_count = 0;
762 
763  if (!q)
764  return NULL;
765  g_return_val_if_fail (q->search_for, NULL);
766  g_return_val_if_fail (q->books, NULL);
767  ENTER (" q=%p", q);
768 
769  /* XXX: Prioritize the query terms? */
770 
771  /* prepare the Query for processing */
772  if (q->changed)
773  {
774  query_clear_compiles (q);
775  compile_terms (q);
776  }
777 
778  /* Maybe log this sucker */
779  if (qof_log_check (log_module, QOF_LOG_DETAIL))
780  qof_query_print (q);
781 
782  /* Now run the query over all the objects and save the results */
783  {
784  QofQueryCB qcb;
785 
786  memset (&qcb, 0, sizeof (qcb));
787  qcb.query = q;
788 
789  /* For each book */
790  for (node = q->books; node; node = node->next)
791  {
792  QofBook *book = node->data;
793  QofBackend *be = book->backend;
794 
795  /* run the query in the backend */
796  if (be)
797  {
798  gpointer compiled_query =
799  g_hash_table_lookup (q->be_compiled, book);
800 
801  if (compiled_query && be->run_query)
802  {
803  (be->run_query) (be, compiled_query);
804  }
805  }
806 
807  /* And then iterate over all the objects */
808  qof_object_foreach (q->search_for, book,
809  (QofEntityForeachCB) check_item_cb, &qcb);
810  }
811 
812  matching_objects = qcb.list;
813  object_count = qcb.count;
814  }
815  PINFO ("matching objects=%p count=%d", matching_objects, object_count);
816 
817  /* There is no absolute need to reverse this list, since it's being
818  * sorted below. However, in the common case, we will be searching
819  * in a confined location where the objects are already in order,
820  * thus reversing will put us in the correct order we want and make
821  * the sorting go much faster.
822  */
823  matching_objects = g_list_reverse (matching_objects);
824 
825  /* Now sort the matching objects based on the search criteria
826  * sortQuery is an unforgivable use of static global data...
827  * I just can't figure out how else to do this sanely.
828  */
829  if (q->primary_sort.comp_fcn || q->primary_sort.obj_cmp ||
830  (q->primary_sort.use_default && q->defaultSort))
831  {
832  sortQuery = q;
833  matching_objects = g_list_sort (matching_objects, sort_func);
834  sortQuery = NULL;
835  }
836 
837  /* Crop the list to limit the number of splits. */
838  if ((object_count > q->max_results) && (q->max_results > -1))
839  {
840  if (q->max_results > 0)
841  {
842  GList *mptr;
843 
844  /* mptr is set to the first node of what will be the new list */
845  mptr =
846  g_list_nth (matching_objects,
847  object_count - q->max_results);
848  /* mptr should not be NULL, but let's be safe */
849  if (mptr != NULL)
850  {
851  if (mptr->prev != NULL)
852  mptr->prev->next = NULL;
853  mptr->prev = NULL;
854  }
855  g_list_free (matching_objects);
856  matching_objects = mptr;
857  }
858  else
859  {
860  /* q->max_results == 0 */
861  g_list_free (matching_objects);
862  matching_objects = NULL;
863  }
864  object_count = q->max_results;
865  }
866 
867  q->changed = 0;
868 
869  g_list_free (q->results);
870  q->results = matching_objects;
871 
872  LEAVE (" q=%p", q);
873  return matching_objects;
874 }
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.

910 {
911  if (!q || !obj_type)
912  return;
913 
914  if (safe_strcmp (q->search_for, obj_type))
915  {
916  q->search_for = (QofIdType) obj_type;
917  q->changed = 1;
918  }
919 }
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.

1336 {
1337  GSList *slist = NULL;
1338  if (!q || !book)
1339  return;
1340 
1341  /* Make sure this book is only in the list once */
1342  if (g_list_index (q->books, book) == -1)
1343  q->books = g_list_prepend (q->books, book);
1344 
1345  slist = g_slist_prepend (slist, QOF_PARAM_GUID);
1346  slist = g_slist_prepend (slist, QOF_PARAM_BOOK);
1347  qof_query_add_guid_match (q, slist,
1348  qof_entity_get_guid ((QofEntity*)book), QOF_QUERY_AND);
1349 }
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.

1294 {
1295  if (!q)
1296  return;
1297  q->max_results = n;
1298 }
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.

1284 {
1285  if (!q)
1286  return;
1287  q->primary_sort.increasing = prim_inc;
1288  q->secondary_sort.increasing = sec_inc;
1289  q->tertiary_sort.increasing = tert_inc;
1290 }
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.

1249 {
1250  if (!q)
1251  return;
1252  if (q->primary_sort.param_list)
1253  g_slist_free (q->primary_sort.param_list);
1254  q->primary_sort.param_list = params1;
1255  q->primary_sort.options = 0;
1256 
1257  if (q->secondary_sort.param_list)
1258  g_slist_free (q->secondary_sort.param_list);
1259  q->secondary_sort.param_list = params2;
1260  q->secondary_sort.options = 0;
1261 
1262  if (q->tertiary_sort.param_list)
1263  g_slist_free (q->tertiary_sort.param_list);
1264  q->tertiary_sort.param_list = params3;
1265  q->tertiary_sort.options = 0;
1266 
1267  q->changed = 1;
1268 }
gboolean qof_query_time_predicate_get_time ( QofQueryPredData pd,
QofTime qt 
)

Retrieve a predicate.

Definition at line 381 of file qofquerycore.c.

383 {
384  query_time_t pdata = (query_time_t) pd;
385 
386  if (pdata->pd.type_name != query_time_type)
387  return FALSE;
388  qt = pdata->qt;
389  return TRUE;
390 }