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 int free_orphans(void *data
, void *user
)
264 struct astrodb_slist
*slist
= data
;
267 struct astrodb_slist
*tmp
= slist
;
274 /*! \fn void astrodb_search_free(astrodb_search* search);
275 * \param search Search
277 * Free's a search and it resources
279 void astrodb_search_free(struct astrodb_search
*search
)
281 astrodb_slist_foreach_free(search
->free_list
, NULL
, NULL
);
282 astrodb_slist_foreach_free(search
->free_slist
, free_orphans
, NULL
);
286 /*! \fn int astrodb_search_add_operator(astrodb_search* search, astrodb_operator op);
287 * \param search Search
289 * \returns 0 on success
291 * Add a node operation in RPN to the search
293 int astrodb_search_add_operator(struct astrodb_search
* search
,
294 enum astrodb_operator op
)
296 struct search_branch
*branch
;
298 branch
= calloc(1, sizeof(struct search_branch
));
302 /* cannnot have lone operator */
303 if (search
->root
== NULL
&&
304 search
->oper_orphans
== NULL
&&
305 search
->comp_orphans
== NULL
) {
310 /* we either have a parent of a comp or op
311 * or a sibling of an op
313 * comparator parent = comp_orphans != NULL, oper_orphans = NULL
314 * operator parent = comp_orphans = NULL, oper_orphans != NULL
317 if (search
->comp_orphans
!= NULL
) {
318 /* comparator parent */
321 branch
->oper
= node_AND_comp
;
324 branch
->oper
= node_OR_comp
;
327 branch
->type
= OP_COMP
;
328 branch
->slist
= search
->comp_orphans
;
330 astrodb_slist_prepend(search
->free_slist
,
331 search
->comp_orphans
);
332 search
->comp_orphans
= NULL
;
334 /* operator parent */
337 branch
->oper
= node_AND_oper
;
340 branch
->oper
= node_OR_oper
;
343 branch
->slist
= search
->oper_orphans
;
344 branch
->type
= OP_OP
;
346 astrodb_slist_prepend(search
->free_slist
,
347 search
->oper_orphans
);
348 search
->oper_orphans
= NULL
;
351 /* we are an orphan ourselves */
352 search
->oper_orphans
=
353 astrodb_slist_prepend(search
->oper_orphans
, branch
);
354 search
->free_list
= astrodb_slist_prepend(search
->free_list
, branch
);
355 search
->start_oper
= branch
;
356 search
->num_search_nodes
++;
361 /*! \fn int astrodb_search_add_comparator(astrodb_search* search, char* field, astrodb_comparator comp, char* value);
362 * \param search Search
363 * \param field Field name
364 * \param comp Comparator
365 * \param value Compare value
367 * Add a comparator in RPN to the search
369 int astrodb_search_add_comparator(struct astrodb_search
*search
, char *field
,
370 enum astrodb_comparator comp
, char *value
)
373 struct search_node
*node
;
376 ctype
= astrodb_table_get_column_type(search
->table
, field
);
377 srch_comp
= get_comparator(comp
, ctype
);
378 if (srch_comp
== NULL
) {
379 astrodb_error("failed to object_slist comparator %d for Ctype %d\n",
383 if (strstr(value
, "*"))
384 srch_comp
= string_eq_wildcard_comp
;
386 node
= calloc(1, sizeof(struct search_node
));
390 node
->offset
= astrodb_table_get_column_offset(search
->table
, field
);
391 node
->comp
= srch_comp
;
398 node
->value
= strdup(value
);
401 node
->value
= calloc(1, sizeof(int));
402 *((int *) node
->value
) = strtol(value
, NULL
, 10);
405 node
->value
= calloc(1, sizeof(float));
406 *((float *) node
->value
) = strtod(value
, NULL
);
409 case CT_DOUBLE_DMS_DEGS
:
410 case CT_DOUBLE_DMS_MINS
:
411 case CT_DOUBLE_DMS_SECS
:
412 case CT_DOUBLE_HMS_HRS
:
413 case CT_DOUBLE_HMS_MINS
:
414 case CT_DOUBLE_HMS_SECS
:
415 node
->value
= calloc(1, sizeof(double));
416 *((double *) node
->value
) = strtod(value
, NULL
);
419 search
->comp_orphans
=
420 astrodb_slist_prepend(search
->comp_orphans
, node
);
421 search
->free_list
= astrodb_slist_prepend(search
->free_list
, node
);
423 astrodb_slist_prepend(search
->free_list
, node
->value
);
424 search
->num_search_nodes
++;
425 search
->start_oper
= NULL
;
430 /*! \fn int astrodb_search_add_custom_comparator(astrodb_search* search, astrodb_custom_comparator comp)
431 * \param search Search
432 * \param comp Custom comparator function
433 * \returns 0 on success
435 * Add a custom search comparator. It should return 1 for a match and 0 for a
438 int astrodb_search_add_custom_comparator(struct astrodb_search
*search
,
439 astrodb_custom_comparator comp
)
444 /*! \fn int astrodb_search_get_results(astrodb_search* search, astrodb_progress progress, astrodb_slist **result, unsigned int src)
445 * \param search Search
446 * \param progress Progress callback
447 * \param result Search results
448 * \param src Object source
450 * Get search results.
452 int astrodb_search_get_results(struct astrodb_search
*search
,
453 struct astrodb_slist
**result
,
456 struct astrodb_slist
*object_slist
= NULL
, *object_slist_
;
457 struct astrodb_slist
*res
= NULL
;
460 if (search
->oper_orphans
) {
461 search
->root
= search
->oper_orphans
;
463 astrodb_slist_prepend(search
->free_slist
,
464 search
->oper_orphans
);
465 search
->oper_orphans
= NULL
;
466 } else if (search
->comp_orphans
) {
467 astrodb_error("unbalanced search - comp orphans exist\n");
471 if (search
->start_oper
== NULL
) {
472 astrodb_error("unbalanced search - no start oper\n");
476 /* operator is root */
477 astrodb_table_get_objects(search
->table
, &object_slist
, src
);
478 object_slist_
= object_slist
;
479 while (object_slist_
) {
480 struct astrodb_slist
*object
= object_slist_
->data
;
481 struct astrodb_slist
*slist
=
482 ((struct search_branch
*) search
->root
->data
)->slist
;
485 if (search
->start_oper
->oper(object
->data
, slist
)) {
487 res
= astrodb_slist_prepend(res
, object
->data
);
490 object
= object
->tail
;
492 object_slist_
= object_slist_
->tail
;
496 astrodb_table_put_objects(object_slist
);
497 *result
= astrodb_slist_prepend(*result
, res
);
501 /*! \fn void astrodb_search_put_results (astrodb_slist *results)
504 * Frees search results
506 void astrodb_search_put_results(struct astrodb_slist
*results
)
508 struct astrodb_slist
*slist
;
513 slist
= results
->data
;
516 struct astrodb_slist
*tmp
= slist
;
523 /*! \fn int astrodb_search_get_hits(astrodb_search* search);
524 * \param search Search
527 * Get the number of search hits.
529 int astrodb_search_get_hits(struct astrodb_search
*search
)
535 /*! \fn int astrodb_search_get_tests(astrodb_search* search);
536 * \param search Search
539 * Get the number of search tests
541 int astrodb_search_get_tests(struct astrodb_search
*search
)
543 return search
->tests
;