4 Copyright (C) Andrew Tridgell 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb tdb backend - indexing
30 * Description: indexing routines for ldb tdb backend
32 * Author: Andrew Tridgell
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include "ldb/ldb_tdb/ldb_tdb.h"
39 #include "ldb/include/ldb_parse.h"
42 find an element in a list, using the given comparison function and
43 assuming that the list is already sorted using comp_fn
45 return -1 if not found, or the index of the first occurance of needle if found
47 static int ldb_list_find(const void *needle,
48 const void *base, size_t nmemb, size_t size,
49 comparison_fn_t comp_fn)
51 const char *base_p = base;
52 size_t min_i, max_i, test_i;
61 while (min_i < max_i) {
64 test_i = (min_i + max_i) / 2;
65 r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
67 /* scan back for first element */
69 comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
85 if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
98 return the dn key to be used for an index
101 static char *ldb_dn_key(struct ldb_context *ldb,
102 const char *attr, const struct ldb_val *value)
106 if (ldb_should_b64_encode(value)) {
107 char *vstr = ldb_base64_encode(ldb, value->data, value->length);
108 if (!vstr) return NULL;
109 ret = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr, vstr);
114 return talloc_asprintf(ldb, "%s:%s:%.*s",
115 LTDB_INDEX, attr, value->length, (char *)value->data);
119 see if a attribute value is in the list of indexed attributes
121 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
122 unsigned int *v_idx, const char *key)
125 for (i=0;i<msg->num_elements;i++) {
126 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
127 const struct ldb_message_element *el =
129 for (j=0;j<el->num_values;j++) {
130 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
142 /* used in sorting dn lists */
143 static int list_cmp(const char **s1, const char **s2)
145 return strcmp(*s1, *s2);
149 return a list of dn's that might match a simple indexed search or
151 static int ltdb_index_dn_simple(struct ldb_module *module,
152 struct ldb_parse_tree *tree,
153 const struct ldb_message *index_list,
154 struct dn_list *list)
156 struct ldb_context *ldb = module->ldb;
160 struct ldb_message *msg;
166 if the value is a wildcard then we can't do a match via indexing
168 if (ltdb_has_wildcard(module, tree->u.simple.attr, &tree->u.simple.value)) {
172 /* if the attribute isn't in the list of indexed attributes then
173 this node needs a full search */
174 if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL, LTDB_IDXATTR) == -1) {
178 /* the attribute is indexed. Pull the list of DNs that match the
180 dn = ldb_dn_key(ldb, tree->u.simple.attr, &tree->u.simple.value);
183 msg = talloc_p(list, struct ldb_message);
188 ret = ltdb_search_dn1(module, dn, msg);
190 if (ret == 0 || ret == -1) {
194 for (i=0;i<msg->num_elements;i++) {
195 struct ldb_message_element *el;
197 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
201 el = &msg->elements[i];
203 list->dn = talloc_array_p(list, char *, el->num_values);
208 for (j=0;j<el->num_values;j++) {
209 list->dn[list->count] =
210 talloc_strdup(list->dn, (char *)el->values[j].data);
211 if (!list->dn[list->count]) {
221 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
227 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
230 return a list of dn's that might match a simple indexed search on
231 the special objectclass attribute
233 static int ltdb_index_dn_objectclass(struct ldb_module *module,
234 struct ldb_parse_tree *tree,
235 const struct ldb_message *index_list,
236 struct dn_list *list)
238 struct ldb_context *ldb = module->ldb;
239 struct ltdb_private *ltdb = module->private_data;
242 const char *target = tree->u.simple.value.data;
247 ret = ltdb_index_dn_simple(module, tree, index_list, list);
249 for (i=0;i<ltdb->cache->subclasses->num_elements;i++) {
250 struct ldb_message_element *el = <db->cache->subclasses->elements[i];
251 if (ldb_attr_cmp(el->name, target) == 0) {
253 for (j=0;j<el->num_values;j++) {
254 struct ldb_parse_tree tree2;
255 struct dn_list *list2;
256 tree2.operation = LDB_OP_SIMPLE;
257 tree2.u.simple.attr = talloc_strdup(list, LTDB_OBJECTCLASS);
258 if (!tree2.u.simple.attr) {
261 tree2.u.simple.value = el->values[j];
262 list2 = talloc_p(list, struct dn_list);
266 if (ltdb_index_dn_objectclass(module, &tree2,
267 index_list, list2) == 1) {
268 if (list->count == 0) {
272 list_union(ldb, list, list2);
276 talloc_free(tree2.u.simple.attr);
285 return a list of dn's that might match a leaf indexed search
287 static int ltdb_index_dn_leaf(struct ldb_module *module,
288 struct ldb_parse_tree *tree,
289 const struct ldb_message *index_list,
290 struct dn_list *list)
292 if (ldb_attr_cmp(tree->u.simple.attr, LTDB_OBJECTCLASS) == 0) {
293 return ltdb_index_dn_objectclass(module, tree, index_list, list);
295 return ltdb_index_dn_simple(module, tree, index_list, list);
302 relies on the lists being sorted
304 static int list_intersect(struct ldb_context *ldb,
305 struct dn_list *list, const struct dn_list *list2)
307 struct dn_list *list3;
310 if (list->count == 0 || list2->count == 0) {
316 list3 = talloc_p(ldb, struct dn_list);
321 list3->dn = talloc_array_p(list3, char *, list->count);
329 for (i=0;i<list->count;i++) {
330 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
331 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
332 list3->dn[list3->count] = talloc_steal(list3->dn, list->dn[i]);
335 talloc_free(list->dn[i]);
339 talloc_free(list->dn);
340 list->dn = talloc_steal(list, list3->dn);
341 list->count = list3->count;
351 relies on the lists being sorted
353 static int list_union(struct ldb_context *ldb,
354 struct dn_list *list, const struct dn_list *list2)
358 unsigned int count = list->count;
360 if (list->count == 0 && list2->count == 0) {
366 d = talloc_realloc_p(list, list->dn, char *, list->count + list2->count);
373 for (i=0;i<list2->count;i++) {
374 if (ldb_list_find(list2->dn[i], list->dn, count,
375 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
376 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
377 if (!list->dn[list->count]) {
385 if (list->count != count) {
386 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
392 static int ltdb_index_dn(struct ldb_module *module,
393 struct ldb_parse_tree *tree,
394 const struct ldb_message *index_list,
395 struct dn_list *list);
401 static int ltdb_index_dn_or(struct ldb_module *module,
402 struct ldb_parse_tree *tree,
403 const struct ldb_message *index_list,
404 struct dn_list *list)
406 struct ldb_context *ldb = module->ldb;
414 for (i=0;i<tree->u.list.num_elements;i++) {
415 struct dn_list *list2;
418 list2 = talloc_p(module, struct dn_list);
423 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
436 talloc_free(list->dn);
443 list->dn = talloc_steal(list, list2->dn);
444 list->count = list2->count;
446 if (list_union(ldb, list, list2) == -1) {
455 if (list->count == 0) {
467 static int ltdb_index_dn_not(struct ldb_module *module,
468 struct ldb_parse_tree *tree,
469 const struct ldb_message *index_list,
470 struct dn_list *list)
472 /* the only way to do an indexed not would be if we could
473 negate the not via another not or if we knew the total
474 number of database elements so we could know that the
475 existing expression covered the whole database.
477 instead, we just give up, and rely on a full index scan
478 (unless an outer & manages to reduce the list)
484 AND two index results
486 static int ltdb_index_dn_and(struct ldb_module *module,
487 struct ldb_parse_tree *tree,
488 const struct ldb_message *index_list,
489 struct dn_list *list)
491 struct ldb_context *ldb = module->ldb;
499 for (i=0;i<tree->u.list.num_elements;i++) {
500 struct dn_list *list2;
503 list2 = talloc_p(module, struct dn_list);
508 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
512 talloc_free(list->dn);
524 talloc_free(list->dn);
525 list->dn = talloc_steal(list, list2->dn);
526 list->count = list2->count;
528 if (list_intersect(ldb, list, list2) == -1) {
536 if (list->count == 0) {
537 talloc_free(list->dn);
546 return a list of dn's that might match a indexed search or
547 -1 if an error. return 0 for no matches, or 1 for matches
549 static int ltdb_index_dn(struct ldb_module *module,
550 struct ldb_parse_tree *tree,
551 const struct ldb_message *index_list,
552 struct dn_list *list)
556 switch (tree->operation) {
558 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
562 ret = ltdb_index_dn_and(module, tree, index_list, list);
566 ret = ltdb_index_dn_or(module, tree, index_list, list);
570 ret = ltdb_index_dn_not(module, tree, index_list, list);
578 filter a candidate dn_list from an indexed search into a set of results
579 extracting just the given attributes
581 static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tree,
583 enum ldb_scope scope,
584 const struct dn_list *dn_list,
585 const char * const attrs[], struct ldb_message ***res)
590 for (i=0;i<dn_list->count;i++) {
591 struct ldb_message *msg;
594 msg = talloc_p(module, struct ldb_message);
599 ret = ltdb_search_dn1(module, dn_list->dn[i], msg);
601 /* the record has disappeared? yes, this can happen */
607 /* an internal error */
613 if (ltdb_message_match(module, msg, tree, base, scope) == 1) {
614 ret = ltdb_add_attr_results(module, msg, attrs, &count, res);
626 search the database with a LDAP-like expression using indexes
627 returns -1 if an indexed search is not possible, in which
628 case the caller should call ltdb_search_full()
630 int ltdb_search_indexed(struct ldb_module *module,
632 enum ldb_scope scope,
633 struct ldb_parse_tree *tree,
634 const char * const attrs[], struct ldb_message ***res)
636 struct ltdb_private *ltdb = module->private_data;
637 struct dn_list *dn_list;
640 if (ltdb->cache->indexlist->num_elements == 0) {
641 /* no index list? must do full search */
645 dn_list = talloc_p(module, struct dn_list);
646 if (dn_list == NULL) {
650 ret = ltdb_index_dn(module, tree, ltdb->cache->indexlist, dn_list);
653 /* we've got a candidate list - now filter by the full tree
654 and extract the needed attributes */
655 ret = ldb_index_filter(module, tree, base, scope, dn_list,
659 talloc_free(dn_list);
665 add a index element where this is the first indexed DN for this value
667 static int ltdb_index_add1_new(struct ldb_context *ldb,
668 struct ldb_message *msg,
669 struct ldb_message_element *el,
672 struct ldb_message_element *el2;
674 /* add another entry */
675 el2 = talloc_realloc_p(msg, msg->elements,
676 struct ldb_message_element, msg->num_elements+1);
682 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
683 if (!msg->elements[msg->num_elements].name) {
686 msg->elements[msg->num_elements].num_values = 0;
687 msg->elements[msg->num_elements].values = talloc_p(msg->elements, struct ldb_val);
688 if (!msg->elements[msg->num_elements].values) {
691 msg->elements[msg->num_elements].values[0].length = strlen(dn);
692 msg->elements[msg->num_elements].values[0].data = dn;
693 msg->elements[msg->num_elements].num_values = 1;
701 add a index element where this is not the first indexed DN for this
704 static int ltdb_index_add1_add(struct ldb_context *ldb,
705 struct ldb_message *msg,
706 struct ldb_message_element *el,
713 /* for multi-valued attributes we can end up with repeats */
714 for (i=0;i<msg->elements[idx].num_values;i++) {
715 if (strcmp(dn, msg->elements[idx].values[i].data) == 0) {
720 v2 = talloc_realloc_p(msg->elements, msg->elements[idx].values,
722 msg->elements[idx].num_values+1);
726 msg->elements[idx].values = v2;
728 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
729 msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
730 msg->elements[idx].num_values++;
736 add an index entry for one message element
738 static int ltdb_index_add1(struct ldb_module *module, char *dn,
739 struct ldb_message_element *el, int v_idx)
741 struct ldb_context *ldb = module->ldb;
742 struct ldb_message *msg;
747 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
752 msg = talloc_p(dn_key, struct ldb_message);
757 ret = ltdb_search_dn1(module, dn_key, msg);
764 msg->dn = talloc_strdup(msg, dn_key);
770 msg->num_elements = 0;
771 msg->elements = NULL;
774 for (i=0;i<msg->num_elements;i++) {
775 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
780 if (i == msg->num_elements) {
781 ret = ltdb_index_add1_new(ldb, msg, el, dn);
783 ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
787 ret = ltdb_store(module, msg, TDB_REPLACE);
796 add the index entries for a new record
799 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
801 struct ltdb_private *ltdb = module->private_data;
805 if (ltdb->cache->indexlist->num_elements == 0) {
806 /* no indexed fields */
810 for (i=0;i<msg->num_elements;i++) {
811 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
816 for (j=0;j<msg->elements[i].num_values;j++) {
817 ret = ltdb_index_add1(module, msg->dn, &msg->elements[i], j);
829 delete an index entry for one message element
831 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
832 struct ldb_message_element *el, int v_idx)
834 struct ldb_context *ldb = module->ldb;
835 struct ldb_message *msg;
840 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
845 msg = talloc_p(dn_key, struct ldb_message);
851 ret = ltdb_search_dn1(module, dn_key, msg);
858 /* it wasn't indexed. Did we have an earlier error? If we did then
864 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
866 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn %s not found in %s\n", dn, dn_key);
867 /* it ain't there. hmmm */
872 if (j != msg->elements[i].num_values - 1) {
873 memmove(&msg->elements[i].values[j],
874 &msg->elements[i].values[j+1],
875 (msg->elements[i].num_values-(j+1)) *
876 sizeof(msg->elements[i].values[0]));
878 msg->elements[i].num_values--;
880 if (msg->elements[i].num_values == 0) {
881 ret = ltdb_delete_noindex(module, dn_key);
883 ret = ltdb_store(module, msg, TDB_REPLACE);
892 delete the index entries for a record
895 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
897 struct ltdb_private *ltdb = module->private_data;
901 /* find the list of indexed fields */
902 if (ltdb->cache->indexlist->num_elements == 0) {
903 /* no indexed fields */
907 for (i=0;i<msg->num_elements;i++) {
908 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
913 for (j=0;j<msg->elements[i].num_values;j++) {
914 ret = ltdb_index_del_value(module, msg->dn, &msg->elements[i], j);
926 traversal function that deletes all @INDEX records
928 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
930 const char *dn = "DN=" LTDB_INDEX ":";
931 if (strncmp(key.dptr, dn, strlen(dn)) == 0) {
932 return tdb_delete(tdb, key);
938 traversal function that adds @INDEX records during a re index
940 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
942 struct ldb_module *module = state;
943 struct ldb_message *msg;
946 if (strncmp(key.dptr, "DN=@", 4) == 0 ||
947 strncmp(key.dptr, "DN=", 3) != 0) {
951 msg = talloc_p(module, struct ldb_message);
956 ret = ltdb_unpack_data(module, &data, msg);
963 msg->dn = key.dptr+3;
966 ret = ltdb_index_add(module, msg);
974 force a complete reindex of the database
976 int ltdb_reindex(struct ldb_module *module)
978 struct ltdb_private *ltdb = module->private_data;
981 if (ltdb_cache_reload(module) != 0) {
985 /* first traverse the database deleting any @INDEX records */
986 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
992 /* now traverse adding any indexes for normal LDB records */
993 ret = tdb_traverse(ltdb->tdb, re_index, module);