2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2008 Liam Girdwood
23 #include <libastrodb/search.h>
24 #include <libastrodb/object.h>
25 #include <libastrodb/adbstdio.h>
27 #define MAX_PARAMS 128
33 /* comparators (type)_(oper)_comp */
34 static int int_lt_comp(void *data
, void *value
)
36 return *(int *) data
< *(int *) value
;
38 static int int_gt_comp(void *data
, void *value
)
40 return *(int *) data
> *(int *) value
;
42 static int int_eq_comp(void *data
, void *value
)
44 return *(int *) data
== *(int *) value
;
46 static int int_ne_comp(void *data
, void *value
)
48 return *(int *) data
!= *(int *) value
;
50 static int float_lt_comp(void *data
, void *value
)
52 return *(float *) data
< *(float *) value
;
54 static int float_gt_comp(void *data
, void *value
)
56 return *(float *) data
> *(float *) value
;
58 static int float_eq_comp(void *data
, void *value
)
60 return *(float *) data
== *(float *) value
;
62 static int float_ne_comp(void *data
, void *value
)
64 return *(float *) data
!= *(float *) value
;
66 static int double_lt_comp(void *data
, void *value
)
68 return *(double *) data
< *(double *) value
;
70 static int double_gt_comp(void *data
, void *value
)
72 return *(double *) data
> *(double *) value
;
74 static int double_eq_comp(void *data
, void *value
)
76 return *(double *) data
== *(double *) value
;
78 static int double_ne_comp(void *data
, void *value
)
80 return *(double *) data
!= *(double *) value
;
82 static int string_lt_comp(void *data
, void *value
)
84 return (strcmp(data
, value
) > 0);
86 static int string_gt_comp(void *data
, void *value
)
88 return (strcmp(data
, value
) < 0);
90 static int string_eq_comp(void *data
, void *value
)
92 return !strcmp(data
, value
);
94 static int string_ne_comp(void *data
, void *value
)
96 return strcmp(data
, value
);
98 static int string_eq_wildcard_comp(void *data
, void *value
)
103 while (*ptr
!= '*') {
108 return !strncmp(data
, value
, i
);
111 /* comparator list operators */
112 static int comp_AND(void *object
, struct astrodb_slist
*slist
)
115 return ((struct search_node
*) slist
->data
)->comp(object
+
116 ((struct search_node
*) slist
->data
)->offset
,
117 ((struct search_node
*) slist
->data
)->value
)
118 && comp_AND(object
, slist
->tail
);
119 return ((struct search_node
*) slist
->data
)->comp(object
+
120 ((struct search_node
*) slist
->data
)->offset
,
121 ((struct search_node
*) slist
->data
)->value
);
124 static int comp_OR(void *object
, struct astrodb_slist
*slist
)
127 return ((struct search_node
*) slist
->data
)->comp(object
+
128 ((struct search_node
*) slist
->data
)->offset
,
129 ((struct search_node
*) slist
->data
)->value
)
130 || comp_OR(object
, slist
->tail
);
131 return ((struct search_node
*) slist
->data
)->comp(object
+
132 ((struct search_node
*) slist
->data
)->offset
,
133 ((struct search_node
*) slist
->data
)->value
);
136 /* node list operators, operate on list of struct search_branch's */
137 static int node_AND_comp(void *object
, struct astrodb_slist
* slist
)
139 struct search_node
*node
= (struct search_node
*) slist
->data
;
142 return node
->comp(object
+ node
->offset
, node
->value
) &&
143 node_AND_comp(object
, slist
->tail
);
144 return node
->comp(object
+ node
->offset
, node
->value
);
147 static int node_OR_comp(void *object
, struct astrodb_slist
* slist
)
149 struct search_node
*node
= (struct search_node
*) slist
->data
;
152 return node
->comp(object
+ node
->offset
, node
->value
) ||
153 node_OR_comp(object
, slist
->tail
);
154 return node
->comp(object
+ node
->offset
, node
->value
);
157 /* node list operators, operate on list of struct search_branch's */
158 static int node_AND_oper(void *object
, struct astrodb_slist
*slist
)
160 struct search_branch
*node
= (struct search_branch
*) slist
->data
;
163 return node
->oper(object
, node
->slist
) &&
164 node_AND_oper(object
, slist
->tail
);
165 return node
->oper(object
, node
->slist
);
168 static int node_OR_oper(void *object
, struct astrodb_slist
* slist
)
170 struct search_branch
*node
= (struct search_branch
*) slist
->data
;
173 return node
->oper(object
, node
->slist
) ||
174 node_OR_oper(object
, slist
->tail
);
175 return node
->oper(object
, node
->slist
);
179 static comp_
get_comparator(enum astrodb_comparator comp
, astrodb_ctype ctype
)
197 return float_lt_comp
;
199 return float_gt_comp
;
201 return float_eq_comp
;
203 return float_ne_comp
;
209 return double_lt_comp
;
211 return double_gt_comp
;
213 return double_eq_comp
;
215 return double_ne_comp
;
221 return string_lt_comp
;
223 return string_gt_comp
;
225 return string_eq_comp
;
227 return string_ne_comp
;
230 case CT_DOUBLE_DMS_DEGS
:
231 case CT_DOUBLE_DMS_MINS
:
232 case CT_DOUBLE_DMS_SECS
:
233 case CT_DOUBLE_HMS_HRS
:
234 case CT_DOUBLE_HMS_MINS
:
235 case CT_DOUBLE_HMS_SECS
:
244 /*! \fn astrodb_search* astrodb_search_create(astrodb_table *table)
245 * \param table dataset
246 * \returns astrodb_search object on success or NULL on failure
248 * Creates an new search object
250 struct astrodb_search
*astrodb_search_create(struct astrodb_table
*table
)
252 struct astrodb_search
*srch
=
253 (struct astrodb_search
*)
254 calloc(1, sizeof(struct astrodb_search
));
262 static void free_orphans(void *data
, void *user
)
264 struct astrodb_slist
*slist
= data
;
267 struct astrodb_slist
*tmp
= slist
;
273 /*! \fn void astrodb_search_free(astrodb_search* search);
274 * \param search Search
276 * Free's a search and it resources
278 void astrodb_search_free(struct astrodb_search
*search
)
280 astrodb_slist_foreach_free(search
->free_list
, NULL
, NULL
);
281 astrodb_slist_foreach_free(search
->free_slist
, free_orphans
, NULL
);
285 /*! \fn int astrodb_search_add_operator(astrodb_search* search, astrodb_operator op);
286 * \param search Search
288 * \returns 0 on success
290 * Add a node operation in RPN to the search
292 int astrodb_search_add_operator(struct astrodb_search
* search
,
293 enum astrodb_operator op
)
295 struct search_branch
*branch
;
297 branch
= calloc(1, sizeof(struct search_branch
));
301 /* cannnot have lone operator */
302 if (search
->root
== NULL
&&
303 search
->oper_orphans
== NULL
&&
304 search
->comp_orphans
== NULL
) {
309 /* we either have a parent of a comp or op
310 * or a sibling of an op
312 * comparator parent = comp_orphans != NULL, oper_orphans = NULL
313 * operator parent = comp_orphans = NULL, oper_orphans != NULL
316 if (search
->comp_orphans
!= NULL
) {
317 /* comparator parent */
320 branch
->oper
= node_AND_comp
;
323 branch
->oper
= node_OR_comp
;
326 branch
->type
= OP_COMP
;
327 branch
->slist
= search
->comp_orphans
;
329 astrodb_slist_prepend(search
->free_slist
,
330 search
->comp_orphans
);
331 search
->comp_orphans
= NULL
;
333 /* operator parent */
336 branch
->oper
= node_AND_oper
;
339 branch
->oper
= node_OR_oper
;
342 branch
->slist
= search
->oper_orphans
;
343 branch
->type
= OP_OP
;
345 astrodb_slist_prepend(search
->free_slist
,
346 search
->oper_orphans
);
347 search
->oper_orphans
= NULL
;
350 /* we are an orphan ourselves */
351 search
->oper_orphans
=
352 astrodb_slist_prepend(search
->oper_orphans
, branch
);
353 search
->free_list
= astrodb_slist_prepend(search
->free_list
, branch
);
354 search
->start_oper
= branch
;
355 search
->num_search_nodes
++;
360 /*! \fn int astrodb_search_add_comparator(astrodb_search* search, char* field, astrodb_comparator comp, char* value);
361 * \param search Search
362 * \param field Field name
363 * \param comp Comparator
364 * \param value Compare value
366 * Add a comparator in RPN to the search
368 int astrodb_search_add_comparator(struct astrodb_search
*search
, char *field
,
369 enum astrodb_comparator comp
, char *value
)
372 struct search_node
*node
;
375 ctype
= astrodb_table_get_column_type(search
->table
, field
);
376 srch_comp
= get_comparator(comp
, ctype
);
377 if (srch_comp
== NULL
) {
378 astrodb_error("failed to object_slist comparator %d for Ctype %d\n",
382 if (strstr(value
, "*"))
383 srch_comp
= string_eq_wildcard_comp
;
385 node
= calloc(1, sizeof(struct search_node
));
389 node
->offset
= astrodb_table_get_column_offset(search
->table
, field
);
390 node
->comp
= srch_comp
;
397 node
->value
= strdup(value
);
400 node
->value
= calloc(1, sizeof(int));
401 *((int *) node
->value
) = strtol(value
, NULL
, 10);
404 node
->value
= calloc(1, sizeof(float));
405 *((float *) node
->value
) = strtod(value
, NULL
);
408 case CT_DOUBLE_DMS_DEGS
:
409 case CT_DOUBLE_DMS_MINS
:
410 case CT_DOUBLE_DMS_SECS
:
411 case CT_DOUBLE_HMS_HRS
:
412 case CT_DOUBLE_HMS_MINS
:
413 case CT_DOUBLE_HMS_SECS
:
414 node
->value
= calloc(1, sizeof(double));
415 *((double *) node
->value
) = strtod(value
, NULL
);
418 search
->comp_orphans
=
419 astrodb_slist_prepend(search
->comp_orphans
, node
);
420 search
->free_list
= astrodb_slist_prepend(search
->free_list
, node
);
422 astrodb_slist_prepend(search
->free_list
, node
->value
);
423 search
->num_search_nodes
++;
424 search
->start_oper
= NULL
;
429 /*! \fn int astrodb_search_add_custom_comparator(astrodb_search* search, astrodb_custom_comparator comp)
430 * \param search Search
431 * \param comp Custom comparator function
432 * \returns 0 on success
434 * Add a custom search comparator. It should return 1 for a match and 0 for a
437 int astrodb_search_add_custom_comparator(struct astrodb_search
*search
,
438 astrodb_custom_comparator comp
)
443 /*! \fn int astrodb_search_get_results(astrodb_search* search, astrodb_progress progress, astrodb_slist **result, unsigned int src)
444 * \param search Search
445 * \param progress Progress callback
446 * \param result Search results
447 * \param src Object source
449 * Get search results.
451 int astrodb_search_get_results(struct astrodb_search
*search
,
452 struct astrodb_slist
**result
,
455 struct astrodb_slist
*object_slist
= NULL
, *object_slist_
;
456 struct astrodb_slist
*res
= NULL
;
459 if (search
->oper_orphans
) {
460 search
->root
= search
->oper_orphans
;
462 astrodb_slist_prepend(search
->free_slist
,
463 search
->oper_orphans
);
464 search
->oper_orphans
= NULL
;
465 } else if (search
->comp_orphans
) {
466 astrodb_error("unbalanced search - comp orphans exist\n");
470 if (search
->start_oper
== NULL
) {
471 astrodb_error("unbalanced search - no start oper\n");
475 /* operator is root */
476 astrodb_table_get_objects(search
->table
, &object_slist
, src
);
477 object_slist_
= object_slist
;
478 while (object_slist_
) {
479 struct astrodb_slist
*object
= object_slist_
->data
;
480 struct astrodb_slist
*slist
=
481 ((struct search_branch
*) search
->root
->data
)->slist
;
484 if (search
->start_oper
->oper(object
->data
, slist
)) {
486 res
= astrodb_slist_prepend(res
, object
->data
);
489 object
= object
->tail
;
491 object_slist_
= object_slist_
->tail
;
495 astrodb_table_put_objects(object_slist
);
496 *result
= astrodb_slist_prepend(*result
, res
);
500 /*! \fn void astrodb_search_put_results (astrodb_slist *results)
503 * Frees search results
505 void astrodb_search_put_results(struct astrodb_slist
*results
)
507 struct astrodb_slist
*slist
;
512 slist
= results
->data
;
515 struct astrodb_slist
*tmp
= slist
;
522 /*! \fn int astrodb_search_get_hits(astrodb_search* search);
523 * \param search Search
526 * Get the number of search hits.
528 int astrodb_search_get_hits(struct astrodb_search
*search
)
534 /*! \fn int astrodb_search_get_tests(astrodb_search* search);
535 * \param search Search
538 * Get the number of search tests
540 int astrodb_search_get_tests(struct astrodb_search
*search
)
542 return search
->tests
;