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 const struct ldb_attrib_handler *h;
108 attr_folded = ldb_casefold(ldb, attr);
113 h = ldb_attrib_handler(ldb, attr);
114 if (h->canonicalise_fn(ldb, ldb, value, &v) != 0) {
115 /* canonicalisation can be refused. For example,
116 a attribute that takes wildcards will refuse to canonicalise
117 if the value contains a wildcard */
118 talloc_free(attr_folded);
121 if (ldb_should_b64_encode(&v)) {
122 char *vstr = ldb_base64_encode(ldb, v.data, v.length);
123 if (!vstr) return NULL;
124 ret = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
126 if (v.data != value->data) {
129 talloc_free(attr_folded);
133 ret = talloc_asprintf(ldb, "%s:%s:%.*s",
134 LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
136 if (v.data != value->data) {
139 talloc_free(attr_folded);
145 see if a attribute value is in the list of indexed attributes
147 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
148 unsigned int *v_idx, const char *key)
151 for (i=0;i<msg->num_elements;i++) {
152 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
153 const struct ldb_message_element *el =
155 for (j=0;j<el->num_values;j++) {
156 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
168 /* used in sorting dn lists */
169 static int list_cmp(const char **s1, const char **s2)
171 return strcmp(*s1, *s2);
175 return a list of dn's that might match a simple indexed search or
177 static int ltdb_index_dn_simple(struct ldb_module *module,
178 struct ldb_parse_tree *tree,
179 const struct ldb_message *index_list,
180 struct dn_list *list)
182 struct ldb_context *ldb = module->ldb;
186 struct ldb_message *msg;
191 /* if the attribute isn't in the list of indexed attributes then
192 this node needs a full search */
193 if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL, LTDB_IDXATTR) == -1) {
197 /* the attribute is indexed. Pull the list of DNs that match the
199 dn = ldb_dn_key(ldb, tree->u.simple.attr, &tree->u.simple.value);
202 msg = talloc(list, struct ldb_message);
207 ret = ltdb_search_dn1(module, dn, msg);
209 if (ret == 0 || ret == -1) {
213 for (i=0;i<msg->num_elements;i++) {
214 struct ldb_message_element *el;
216 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
220 el = &msg->elements[i];
222 list->dn = talloc_array(list, char *, el->num_values);
227 for (j=0;j<el->num_values;j++) {
228 list->dn[list->count] =
229 talloc_strdup(list->dn, (char *)el->values[j].data);
230 if (!list->dn[list->count]) {
239 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
245 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
248 return a list of dn's that might match a simple indexed search on
249 the special objectclass attribute
251 static int ltdb_index_dn_objectclass(struct ldb_module *module,
252 struct ldb_parse_tree *tree,
253 const struct ldb_message *index_list,
254 struct dn_list *list)
256 struct ldb_context *ldb = module->ldb;
259 const char *target = tree->u.simple.value.data;
260 const char **subclasses;
265 ret = ltdb_index_dn_simple(module, tree, index_list, list);
267 subclasses = ldb_subclass_list(module->ldb, target);
269 if (subclasses == NULL) {
273 for (i=0;subclasses[i];i++) {
274 struct ldb_parse_tree tree2;
275 struct dn_list *list2;
276 tree2.operation = LDB_OP_SIMPLE;
277 tree2.u.simple.attr = talloc_strdup(list, LTDB_OBJECTCLASS);
278 if (!tree2.u.simple.attr) {
281 tree2.u.simple.value.data = talloc_strdup(tree2.u.simple.attr, subclasses[i]);
282 if (tree2.u.simple.value.data == NULL) {
285 tree2.u.simple.value.length = strlen(subclasses[i]);
286 list2 = talloc(list, struct dn_list);
290 if (ltdb_index_dn_objectclass(module, &tree2,
291 index_list, list2) == 1) {
292 if (list->count == 0) {
296 list_union(ldb, list, list2);
300 talloc_free(tree2.u.simple.attr);
307 return a list of dn's that might match a leaf indexed search
309 static int ltdb_index_dn_leaf(struct ldb_module *module,
310 struct ldb_parse_tree *tree,
311 const struct ldb_message *index_list,
312 struct dn_list *list)
314 if (ldb_attr_cmp(tree->u.simple.attr, LTDB_OBJECTCLASS) == 0) {
315 return ltdb_index_dn_objectclass(module, tree, index_list, list);
317 return ltdb_index_dn_simple(module, tree, index_list, list);
324 relies on the lists being sorted
326 static int list_intersect(struct ldb_context *ldb,
327 struct dn_list *list, const struct dn_list *list2)
329 struct dn_list *list3;
332 if (list->count == 0 || list2->count == 0) {
337 list3 = talloc(ldb, struct dn_list);
342 list3->dn = talloc_array(list3, char *, list->count);
349 for (i=0;i<list->count;i++) {
350 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
351 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
352 list3->dn[list3->count] = talloc_steal(list3->dn, list->dn[i]);
355 talloc_free(list->dn[i]);
359 talloc_free(list->dn);
360 list->dn = talloc_steal(list, list3->dn);
361 list->count = list3->count;
371 relies on the lists being sorted
373 static int list_union(struct ldb_context *ldb,
374 struct dn_list *list, const struct dn_list *list2)
378 unsigned int count = list->count;
380 if (list->count == 0 && list2->count == 0) {
385 d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
391 for (i=0;i<list2->count;i++) {
392 if (ldb_list_find(list2->dn[i], list->dn, count,
393 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
394 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
395 if (!list->dn[list->count]) {
402 if (list->count != count) {
403 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
409 static int ltdb_index_dn(struct ldb_module *module,
410 struct ldb_parse_tree *tree,
411 const struct ldb_message *index_list,
412 struct dn_list *list);
418 static int ltdb_index_dn_or(struct ldb_module *module,
419 struct ldb_parse_tree *tree,
420 const struct ldb_message *index_list,
421 struct dn_list *list)
423 struct ldb_context *ldb = module->ldb;
431 for (i=0;i<tree->u.list.num_elements;i++) {
432 struct dn_list *list2;
435 list2 = talloc(module, struct dn_list);
440 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
453 talloc_free(list->dn);
460 list->dn = talloc_steal(list, list2->dn);
461 list->count = list2->count;
463 if (list_union(ldb, list, list2) == -1) {
472 if (list->count == 0) {
483 static int ltdb_index_dn_not(struct ldb_module *module,
484 struct ldb_parse_tree *tree,
485 const struct ldb_message *index_list,
486 struct dn_list *list)
488 /* the only way to do an indexed not would be if we could
489 negate the not via another not or if we knew the total
490 number of database elements so we could know that the
491 existing expression covered the whole database.
493 instead, we just give up, and rely on a full index scan
494 (unless an outer & manages to reduce the list)
500 AND two index results
502 static int ltdb_index_dn_and(struct ldb_module *module,
503 struct ldb_parse_tree *tree,
504 const struct ldb_message *index_list,
505 struct dn_list *list)
507 struct ldb_context *ldb = module->ldb;
515 for (i=0;i<tree->u.list.num_elements;i++) {
516 struct dn_list *list2;
519 list2 = talloc(module, struct dn_list);
524 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
528 talloc_free(list->dn);
540 talloc_free(list->dn);
541 list->dn = talloc_steal(list, list2->dn);
542 list->count = list2->count;
544 if (list_intersect(ldb, list, list2) == -1) {
552 if (list->count == 0) {
553 talloc_free(list->dn);
562 return a list of dn's that might match a indexed search or
563 -1 if an error. return 0 for no matches, or 1 for matches
565 static int ltdb_index_dn(struct ldb_module *module,
566 struct ldb_parse_tree *tree,
567 const struct ldb_message *index_list,
568 struct dn_list *list)
572 switch (tree->operation) {
574 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
578 case LDB_OP_SUBSTRING:
579 case LDB_OP_EXTENDED:
580 /* we can't index with fancy bitops yet */
585 ret = ltdb_index_dn_and(module, tree, index_list, list);
589 ret = ltdb_index_dn_or(module, tree, index_list, list);
593 ret = ltdb_index_dn_not(module, tree, index_list, list);
601 filter a candidate dn_list from an indexed search into a set of results
602 extracting just the given attributes
604 static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tree,
606 enum ldb_scope scope,
607 const struct dn_list *dn_list,
608 const char * const attrs[], struct ldb_message ***res)
613 for (i=0;i<dn_list->count;i++) {
614 struct ldb_message *msg;
617 msg = talloc(module, struct ldb_message);
622 ret = ltdb_search_dn1(module, dn_list->dn[i], msg);
624 /* the record has disappeared? yes, this can happen */
630 /* an internal error */
636 if (ldb_match_msg(module->ldb, msg, tree, base, scope) == 1) {
637 ret = ltdb_add_attr_results(module, msg, attrs, &count, res);
649 search the database with a LDAP-like expression using indexes
650 returns -1 if an indexed search is not possible, in which
651 case the caller should call ltdb_search_full()
653 int ltdb_search_indexed(struct ldb_module *module,
655 enum ldb_scope scope,
656 struct ldb_parse_tree *tree,
657 const char * const attrs[], struct ldb_message ***res)
659 struct ltdb_private *ltdb = module->private_data;
660 struct dn_list *dn_list;
663 if (ltdb->cache->indexlist->num_elements == 0) {
664 /* no index list? must do full search */
668 dn_list = talloc(module, struct dn_list);
669 if (dn_list == NULL) {
673 ret = ltdb_index_dn(module, tree, ltdb->cache->indexlist, dn_list);
676 /* we've got a candidate list - now filter by the full tree
677 and extract the needed attributes */
678 ret = ldb_index_filter(module, tree, base, scope, dn_list,
682 talloc_free(dn_list);
688 add a index element where this is the first indexed DN for this value
690 static int ltdb_index_add1_new(struct ldb_context *ldb,
691 struct ldb_message *msg,
692 struct ldb_message_element *el,
695 struct ldb_message_element *el2;
697 /* add another entry */
698 el2 = talloc_realloc(msg, msg->elements,
699 struct ldb_message_element, msg->num_elements+1);
705 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
706 if (!msg->elements[msg->num_elements].name) {
709 msg->elements[msg->num_elements].num_values = 0;
710 msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
711 if (!msg->elements[msg->num_elements].values) {
714 msg->elements[msg->num_elements].values[0].length = strlen(dn);
715 msg->elements[msg->num_elements].values[0].data = dn;
716 msg->elements[msg->num_elements].num_values = 1;
724 add a index element where this is not the first indexed DN for this
727 static int ltdb_index_add1_add(struct ldb_context *ldb,
728 struct ldb_message *msg,
729 struct ldb_message_element *el,
736 /* for multi-valued attributes we can end up with repeats */
737 for (i=0;i<msg->elements[idx].num_values;i++) {
738 if (strcmp(dn, msg->elements[idx].values[i].data) == 0) {
743 v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
745 msg->elements[idx].num_values+1);
749 msg->elements[idx].values = v2;
751 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
752 msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
753 msg->elements[idx].num_values++;
759 add an index entry for one message element
761 static int ltdb_index_add1(struct ldb_module *module, char *dn,
762 struct ldb_message_element *el, int v_idx)
764 struct ldb_context *ldb = module->ldb;
765 struct ldb_message *msg;
770 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
775 msg = talloc(dn_key, struct ldb_message);
780 ret = ltdb_search_dn1(module, dn_key, msg);
787 msg->dn = talloc_strdup(msg, dn_key);
793 msg->num_elements = 0;
794 msg->elements = NULL;
797 for (i=0;i<msg->num_elements;i++) {
798 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
803 if (i == msg->num_elements) {
804 ret = ltdb_index_add1_new(ldb, msg, el, dn);
806 ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
810 ret = ltdb_store(module, msg, TDB_REPLACE);
819 add the index entries for a new record
822 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
824 struct ltdb_private *ltdb = module->private_data;
828 if (msg->dn[0] == '@') {
832 if (ltdb->cache->indexlist->num_elements == 0) {
833 /* no indexed fields */
837 for (i=0;i<msg->num_elements;i++) {
838 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
843 for (j=0;j<msg->elements[i].num_values;j++) {
844 ret = ltdb_index_add1(module, msg->dn, &msg->elements[i], j);
856 delete an index entry for one message element
858 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
859 struct ldb_message_element *el, int v_idx)
861 struct ldb_context *ldb = module->ldb;
862 struct ldb_message *msg;
871 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
876 msg = talloc(dn_key, struct ldb_message);
882 ret = ltdb_search_dn1(module, dn_key, msg);
889 /* it wasn't indexed. Did we have an earlier error? If we did then
895 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
897 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn %s not found in %s\n", dn, dn_key);
898 /* it ain't there. hmmm */
903 if (j != msg->elements[i].num_values - 1) {
904 memmove(&msg->elements[i].values[j],
905 &msg->elements[i].values[j+1],
906 (msg->elements[i].num_values-(j+1)) *
907 sizeof(msg->elements[i].values[0]));
909 msg->elements[i].num_values--;
911 if (msg->elements[i].num_values == 0) {
912 ret = ltdb_delete_noindex(module, dn_key);
914 ret = ltdb_store(module, msg, TDB_REPLACE);
923 delete the index entries for a record
926 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
928 struct ltdb_private *ltdb = module->private_data;
932 if (msg->dn[0] == '@') {
936 /* find the list of indexed fields */
937 if (ltdb->cache->indexlist->num_elements == 0) {
938 /* no indexed fields */
942 for (i=0;i<msg->num_elements;i++) {
943 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
948 for (j=0;j<msg->elements[i].num_values;j++) {
949 ret = ltdb_index_del_value(module, msg->dn, &msg->elements[i], j);
961 traversal function that deletes all @INDEX records
963 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
965 const char *dn = "DN=" LTDB_INDEX ":";
966 if (strncmp(key.dptr, dn, strlen(dn)) == 0) {
967 return tdb_delete(tdb, key);
973 traversal function that adds @INDEX records during a re index
975 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
977 struct ldb_module *module = state;
978 struct ldb_message *msg;
982 if (strncmp(key.dptr, "DN=@", 4) == 0 ||
983 strncmp(key.dptr, "DN=", 3) != 0) {
987 msg = talloc(module, struct ldb_message);
992 ret = ltdb_unpack_data(module, &data, msg);
998 /* check if the DN key has changed, perhaps due to the
999 case insensitivity of an element changing */
1000 key2 = ltdb_key(module, msg->dn);
1001 if (strcmp(key2.dptr, key.dptr) != 0) {
1002 tdb_delete(tdb, key);
1003 tdb_store(tdb, key2, data, 0);
1005 talloc_free(key2.dptr);
1008 msg->dn = key.dptr+3;
1011 ret = ltdb_index_add(module, msg);
1019 force a complete reindex of the database
1021 int ltdb_reindex(struct ldb_module *module)
1023 struct ltdb_private *ltdb = module->private_data;
1026 if (ltdb_cache_reload(module) != 0) {
1030 /* first traverse the database deleting any @INDEX records */
1031 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
1037 /* now traverse adding any indexes for normal LDB records */
1038 ret = tdb_traverse(ltdb->tdb, re_index, module);