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"
41 find an element in a list, using the given comparison function and
42 assuming that the list is already sorted using comp_fn
44 return -1 if not found, or the index of the first occurance of needle if found
46 static int ldb_list_find(const void *needle,
47 const void *base, size_t nmemb, size_t size,
48 comparison_fn_t comp_fn)
50 const char *base_p = base;
51 size_t min_i, max_i, test_i;
60 while (min_i < max_i) {
63 test_i = (min_i + max_i) / 2;
64 r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
66 /* scan back for first element */
68 comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
84 if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
97 return the dn key to be used for an index
100 static char *ldb_dn_key(struct ldb_context *ldb,
101 const char *attr, const struct ldb_val *value)
105 if (ldb_should_b64_encode(value)) {
106 char *vstr = ldb_base64_encode(ldb, value->data, value->length);
107 if (!vstr) return NULL;
108 ret = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr, vstr);
113 return talloc_asprintf(ldb, "%s:%s:%.*s",
114 LTDB_INDEX, attr, value->length, (char *)value->data);
118 see if a attribute value is in the list of indexed attributes
120 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
121 unsigned int *v_idx, const char *key)
124 for (i=0;i<msg->num_elements;i++) {
125 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
126 const struct ldb_message_element *el =
128 for (j=0;j<el->num_values;j++) {
129 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
141 /* used in sorting dn lists */
142 static int list_cmp(const char **s1, const char **s2)
144 return strcmp(*s1, *s2);
148 return a list of dn's that might match a simple indexed search or
150 static int ltdb_index_dn_simple(struct ldb_module *module,
151 struct ldb_parse_tree *tree,
152 const struct ldb_message *index_list,
153 struct dn_list *list)
155 struct ldb_context *ldb = module->ldb;
159 struct ldb_message *msg;
165 if the value is a wildcard then we can't do a match via indexing
167 if (ltdb_has_wildcard(module, tree->u.simple.attr, &tree->u.simple.value)) {
171 /* if the attribute isn't in the list of indexed attributes then
172 this node needs a full search */
173 if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL, LTDB_IDXATTR) == -1) {
177 /* the attribute is indexed. Pull the list of DNs that match the
179 dn = ldb_dn_key(ldb, tree->u.simple.attr, &tree->u.simple.value);
182 msg = talloc(list, struct ldb_message);
187 ret = ltdb_search_dn1(module, dn, msg);
189 if (ret == 0 || ret == -1) {
193 for (i=0;i<msg->num_elements;i++) {
194 struct ldb_message_element *el;
196 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
200 el = &msg->elements[i];
202 list->dn = talloc_array(list, char *, el->num_values);
207 for (j=0;j<el->num_values;j++) {
208 list->dn[list->count] =
209 talloc_strdup(list->dn, (char *)el->values[j].data);
210 if (!list->dn[list->count]) {
219 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
225 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
228 return a list of dn's that might match a simple indexed search on
229 the special objectclass attribute
231 static int ltdb_index_dn_objectclass(struct ldb_module *module,
232 struct ldb_parse_tree *tree,
233 const struct ldb_message *index_list,
234 struct dn_list *list)
236 struct ldb_context *ldb = module->ldb;
237 struct ltdb_private *ltdb = module->private_data;
240 const char *target = tree->u.simple.value.data;
245 ret = ltdb_index_dn_simple(module, tree, index_list, list);
247 for (i=0;i<ltdb->cache->subclasses->num_elements;i++) {
248 struct ldb_message_element *el = <db->cache->subclasses->elements[i];
249 if (ldb_attr_cmp(el->name, target) == 0) {
251 for (j=0;j<el->num_values;j++) {
252 struct ldb_parse_tree tree2;
253 struct dn_list *list2;
254 tree2.operation = LDB_OP_SIMPLE;
255 tree2.u.simple.attr = talloc_strdup(list, LTDB_OBJECTCLASS);
256 if (!tree2.u.simple.attr) {
259 tree2.u.simple.value = el->values[j];
260 list2 = talloc(list, struct dn_list);
264 if (ltdb_index_dn_objectclass(module, &tree2,
265 index_list, list2) == 1) {
266 if (list->count == 0) {
270 list_union(ldb, list, list2);
274 talloc_free(tree2.u.simple.attr);
283 return a list of dn's that might match a leaf indexed search
285 static int ltdb_index_dn_leaf(struct ldb_module *module,
286 struct ldb_parse_tree *tree,
287 const struct ldb_message *index_list,
288 struct dn_list *list)
290 if (ldb_attr_cmp(tree->u.simple.attr, LTDB_OBJECTCLASS) == 0) {
291 return ltdb_index_dn_objectclass(module, tree, index_list, list);
293 return ltdb_index_dn_simple(module, tree, index_list, list);
300 relies on the lists being sorted
302 static int list_intersect(struct ldb_context *ldb,
303 struct dn_list *list, const struct dn_list *list2)
305 struct dn_list *list3;
308 if (list->count == 0 || list2->count == 0) {
313 list3 = talloc(ldb, struct dn_list);
318 list3->dn = talloc_array(list3, char *, list->count);
325 for (i=0;i<list->count;i++) {
326 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
327 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
328 list3->dn[list3->count] = talloc_steal(list3->dn, list->dn[i]);
331 talloc_free(list->dn[i]);
335 talloc_free(list->dn);
336 list->dn = talloc_steal(list, list3->dn);
337 list->count = list3->count;
347 relies on the lists being sorted
349 static int list_union(struct ldb_context *ldb,
350 struct dn_list *list, const struct dn_list *list2)
354 unsigned int count = list->count;
356 if (list->count == 0 && list2->count == 0) {
361 d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
367 for (i=0;i<list2->count;i++) {
368 if (ldb_list_find(list2->dn[i], list->dn, count,
369 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
370 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
371 if (!list->dn[list->count]) {
378 if (list->count != count) {
379 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
385 static int ltdb_index_dn(struct ldb_module *module,
386 struct ldb_parse_tree *tree,
387 const struct ldb_message *index_list,
388 struct dn_list *list);
394 static int ltdb_index_dn_or(struct ldb_module *module,
395 struct ldb_parse_tree *tree,
396 const struct ldb_message *index_list,
397 struct dn_list *list)
399 struct ldb_context *ldb = module->ldb;
407 for (i=0;i<tree->u.list.num_elements;i++) {
408 struct dn_list *list2;
411 list2 = talloc(module, struct dn_list);
416 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
429 talloc_free(list->dn);
436 list->dn = talloc_steal(list, list2->dn);
437 list->count = list2->count;
439 if (list_union(ldb, list, list2) == -1) {
448 if (list->count == 0) {
459 static int ltdb_index_dn_not(struct ldb_module *module,
460 struct ldb_parse_tree *tree,
461 const struct ldb_message *index_list,
462 struct dn_list *list)
464 /* the only way to do an indexed not would be if we could
465 negate the not via another not or if we knew the total
466 number of database elements so we could know that the
467 existing expression covered the whole database.
469 instead, we just give up, and rely on a full index scan
470 (unless an outer & manages to reduce the list)
476 AND two index results
478 static int ltdb_index_dn_and(struct ldb_module *module,
479 struct ldb_parse_tree *tree,
480 const struct ldb_message *index_list,
481 struct dn_list *list)
483 struct ldb_context *ldb = module->ldb;
491 for (i=0;i<tree->u.list.num_elements;i++) {
492 struct dn_list *list2;
495 list2 = talloc(module, struct dn_list);
500 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
504 talloc_free(list->dn);
516 talloc_free(list->dn);
517 list->dn = talloc_steal(list, list2->dn);
518 list->count = list2->count;
520 if (list_intersect(ldb, list, list2) == -1) {
528 if (list->count == 0) {
529 talloc_free(list->dn);
538 return a list of dn's that might match a indexed search or
539 -1 if an error. return 0 for no matches, or 1 for matches
541 static int ltdb_index_dn(struct ldb_module *module,
542 struct ldb_parse_tree *tree,
543 const struct ldb_message *index_list,
544 struct dn_list *list)
548 switch (tree->operation) {
550 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
554 ret = ltdb_index_dn_and(module, tree, index_list, list);
558 ret = ltdb_index_dn_or(module, tree, index_list, list);
562 ret = ltdb_index_dn_not(module, tree, index_list, list);
570 filter a candidate dn_list from an indexed search into a set of results
571 extracting just the given attributes
573 static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tree,
575 enum ldb_scope scope,
576 const struct dn_list *dn_list,
577 const char * const attrs[], struct ldb_message ***res)
582 for (i=0;i<dn_list->count;i++) {
583 struct ldb_message *msg;
586 msg = talloc(module, struct ldb_message);
591 ret = ltdb_search_dn1(module, dn_list->dn[i], msg);
593 /* the record has disappeared? yes, this can happen */
599 /* an internal error */
605 if (ltdb_message_match(module, msg, tree, base, scope) == 1) {
606 ret = ltdb_add_attr_results(module, msg, attrs, &count, res);
618 search the database with a LDAP-like expression using indexes
619 returns -1 if an indexed search is not possible, in which
620 case the caller should call ltdb_search_full()
622 int ltdb_search_indexed(struct ldb_module *module,
624 enum ldb_scope scope,
625 struct ldb_parse_tree *tree,
626 const char * const attrs[], struct ldb_message ***res)
628 struct ltdb_private *ltdb = module->private_data;
629 struct dn_list *dn_list;
632 if (ltdb->cache->indexlist->num_elements == 0) {
633 /* no index list? must do full search */
637 dn_list = talloc(module, struct dn_list);
638 if (dn_list == NULL) {
642 ret = ltdb_index_dn(module, tree, ltdb->cache->indexlist, dn_list);
645 /* we've got a candidate list - now filter by the full tree
646 and extract the needed attributes */
647 ret = ldb_index_filter(module, tree, base, scope, dn_list,
651 talloc_free(dn_list);
657 add a index element where this is the first indexed DN for this value
659 static int ltdb_index_add1_new(struct ldb_context *ldb,
660 struct ldb_message *msg,
661 struct ldb_message_element *el,
664 struct ldb_message_element *el2;
666 /* add another entry */
667 el2 = talloc_realloc(msg, msg->elements,
668 struct ldb_message_element, msg->num_elements+1);
674 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
675 if (!msg->elements[msg->num_elements].name) {
678 msg->elements[msg->num_elements].num_values = 0;
679 msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
680 if (!msg->elements[msg->num_elements].values) {
683 msg->elements[msg->num_elements].values[0].length = strlen(dn);
684 msg->elements[msg->num_elements].values[0].data = dn;
685 msg->elements[msg->num_elements].num_values = 1;
693 add a index element where this is not the first indexed DN for this
696 static int ltdb_index_add1_add(struct ldb_context *ldb,
697 struct ldb_message *msg,
698 struct ldb_message_element *el,
705 /* for multi-valued attributes we can end up with repeats */
706 for (i=0;i<msg->elements[idx].num_values;i++) {
707 if (strcmp(dn, msg->elements[idx].values[i].data) == 0) {
712 v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
714 msg->elements[idx].num_values+1);
718 msg->elements[idx].values = v2;
720 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
721 msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
722 msg->elements[idx].num_values++;
728 add an index entry for one message element
730 static int ltdb_index_add1(struct ldb_module *module, char *dn,
731 struct ldb_message_element *el, int v_idx)
733 struct ldb_context *ldb = module->ldb;
734 struct ldb_message *msg;
739 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
744 msg = talloc(dn_key, struct ldb_message);
749 ret = ltdb_search_dn1(module, dn_key, msg);
756 msg->dn = talloc_strdup(msg, dn_key);
762 msg->num_elements = 0;
763 msg->elements = NULL;
766 for (i=0;i<msg->num_elements;i++) {
767 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
772 if (i == msg->num_elements) {
773 ret = ltdb_index_add1_new(ldb, msg, el, dn);
775 ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
779 ret = ltdb_store(module, msg, TDB_REPLACE);
788 add the index entries for a new record
791 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
793 struct ltdb_private *ltdb = module->private_data;
797 if (ltdb->cache->indexlist->num_elements == 0) {
798 /* no indexed fields */
802 for (i=0;i<msg->num_elements;i++) {
803 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
808 for (j=0;j<msg->elements[i].num_values;j++) {
809 ret = ltdb_index_add1(module, msg->dn, &msg->elements[i], j);
821 delete an index entry for one message element
823 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
824 struct ldb_message_element *el, int v_idx)
826 struct ldb_context *ldb = module->ldb;
827 struct ldb_message *msg;
832 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
837 msg = talloc(dn_key, struct ldb_message);
843 ret = ltdb_search_dn1(module, dn_key, msg);
850 /* it wasn't indexed. Did we have an earlier error? If we did then
856 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
858 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn %s not found in %s\n", dn, dn_key);
859 /* it ain't there. hmmm */
864 if (j != msg->elements[i].num_values - 1) {
865 memmove(&msg->elements[i].values[j],
866 &msg->elements[i].values[j+1],
867 (msg->elements[i].num_values-(j+1)) *
868 sizeof(msg->elements[i].values[0]));
870 msg->elements[i].num_values--;
872 if (msg->elements[i].num_values == 0) {
873 ret = ltdb_delete_noindex(module, dn_key);
875 ret = ltdb_store(module, msg, TDB_REPLACE);
884 delete the index entries for a record
887 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
889 struct ltdb_private *ltdb = module->private_data;
893 /* find the list of indexed fields */
894 if (ltdb->cache->indexlist->num_elements == 0) {
895 /* no indexed fields */
899 for (i=0;i<msg->num_elements;i++) {
900 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
905 for (j=0;j<msg->elements[i].num_values;j++) {
906 ret = ltdb_index_del_value(module, msg->dn, &msg->elements[i], j);
918 traversal function that deletes all @INDEX records
920 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
922 const char *dn = "DN=" LTDB_INDEX ":";
923 if (strncmp(key.dptr, dn, strlen(dn)) == 0) {
924 return tdb_delete(tdb, key);
930 traversal function that adds @INDEX records during a re index
932 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
934 struct ldb_module *module = state;
935 struct ldb_message *msg;
939 if (strncmp(key.dptr, "DN=@", 4) == 0 ||
940 strncmp(key.dptr, "DN=", 3) != 0) {
944 msg = talloc(module, struct ldb_message);
949 ret = ltdb_unpack_data(module, &data, msg);
955 /* check if the DN key has changed, perhaps due to the
956 case insensitivity of an element changing */
957 key2 = ltdb_key(module, msg->dn);
958 if (strcmp(key2.dptr, key.dptr) != 0) {
959 tdb_delete(tdb, key);
960 tdb_store(tdb, key2, data, 0);
962 talloc_free(key2.dptr);
965 msg->dn = key.dptr+3;
968 ret = ltdb_index_add(module, msg);
976 force a complete reindex of the database
978 int ltdb_reindex(struct ldb_module *module)
980 struct ltdb_private *ltdb = module->private_data;
983 if (ltdb_cache_reload(module) != 0) {
987 /* first traverse the database deleting any @INDEX records */
988 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
994 /* now traverse adding any indexes for normal LDB records */
995 ret = tdb_traverse(ltdb->tdb, re_index, module);