r19964: make debuging easier and report usefull error messages
[Samba/ekacnet.git] / source4 / lib / ldb / ldb_tdb / ldb_index.c
blob99288d2b5f48b24bc7783f1868fd985629d73e8d
1 /*
2 ldb database library
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
8 ** under the LGPL
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
26 * Name: ldb
28 * Component: ldb tdb backend - indexing
30 * Description: indexing routines for ldb tdb backend
32 * Author: Andrew Tridgell
35 #include "includes.h"
36 #include "ldb/include/includes.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;
53 if (nmemb == 0) {
54 return -1;
57 min_i = 0;
58 max_i = nmemb-1;
60 while (min_i < max_i) {
61 int r;
63 test_i = (min_i + max_i) / 2;
64 /* the following cast looks strange, but is
65 correct. The key to understanding it is that base_p
66 is a pointer to an array of pointers, so we have to
67 dereference it after casting to void **. The strange
68 const in the middle gives us the right type of pointer
69 after the dereference (tridge) */
70 r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
71 if (r == 0) {
72 /* scan back for first element */
73 while (test_i > 0 &&
74 comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
75 test_i--;
77 return test_i;
79 if (r < 0) {
80 if (test_i == 0) {
81 return -1;
83 max_i = test_i - 1;
85 if (r > 0) {
86 min_i = test_i + 1;
90 if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
91 return min_i;
94 return -1;
97 struct dn_list {
98 unsigned int count;
99 char **dn;
103 return the dn key to be used for an index
104 caller frees
106 static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb,
107 const char *attr, const struct ldb_val *value)
109 struct ldb_dn *ret;
110 struct ldb_val v;
111 const struct ldb_attrib_handler *h;
112 char *attr_folded;
113 int r;
115 attr_folded = ldb_attr_casefold(ldb, attr);
116 if (!attr_folded) {
117 return NULL;
120 h = ldb_attrib_handler(ldb, attr);
121 r = h->canonicalise_fn(ldb, ldb, value, &v);
122 if (r != LDB_SUCCESS) {
123 /* canonicalisation can be refused. For example,
124 a attribute that takes wildcards will refuse to canonicalise
125 if the value contains a wildcard */
126 ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s:%s",
127 attr, ldb_strerror(r), ldb_errstring(ldb));
128 talloc_free(attr_folded);
129 return NULL;
131 if (ldb_should_b64_encode(&v)) {
132 char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
133 if (!vstr) return NULL;
134 ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
135 talloc_free(vstr);
136 } else {
137 ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
140 if (v.data != value->data) {
141 talloc_free(v.data);
143 talloc_free(attr_folded);
145 return ret;
149 see if a attribute value is in the list of indexed attributes
151 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
152 unsigned int *v_idx, const char *key)
154 unsigned int i, j;
155 for (i=0;i<msg->num_elements;i++) {
156 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
157 const struct ldb_message_element *el =
158 &msg->elements[i];
159 for (j=0;j<el->num_values;j++) {
160 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
161 if (v_idx) {
162 *v_idx = j;
164 return i;
169 return -1;
172 /* used in sorting dn lists */
173 static int list_cmp(const char **s1, const char **s2)
175 return strcmp(*s1, *s2);
179 return a list of dn's that might match a simple indexed search or
181 static int ltdb_index_dn_simple(struct ldb_module *module,
182 const struct ldb_parse_tree *tree,
183 const struct ldb_message *index_list,
184 struct dn_list *list)
186 struct ldb_context *ldb = module->ldb;
187 struct ldb_dn *dn;
188 int ret;
189 unsigned int i, j;
190 struct ldb_message *msg;
192 list->count = 0;
193 list->dn = NULL;
195 /* if the attribute isn't in the list of indexed attributes then
196 this node needs a full search */
197 if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) {
198 return -1;
201 /* the attribute is indexed. Pull the list of DNs that match the
202 search criterion */
203 dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value);
204 if (!dn) return -1;
206 msg = talloc(list, struct ldb_message);
207 if (msg == NULL) {
208 return -1;
211 ret = ltdb_search_dn1(module, dn, msg);
212 talloc_free(dn);
213 if (ret == 0 || ret == -1) {
214 return ret;
217 for (i=0;i<msg->num_elements;i++) {
218 struct ldb_message_element *el;
220 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
221 continue;
224 el = &msg->elements[i];
226 list->dn = talloc_array(list, char *, el->num_values);
227 if (!list->dn) {
228 talloc_free(msg);
229 return -1;
232 for (j=0;j<el->num_values;j++) {
233 list->dn[list->count] =
234 talloc_strdup(list->dn, (char *)el->values[j].data);
235 if (!list->dn[list->count]) {
236 talloc_free(msg);
237 return -1;
239 list->count++;
243 talloc_free(msg);
245 if (list->count > 1) {
246 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
249 return 1;
253 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
256 return a list of dn's that might match a simple indexed search on
257 the special objectclass attribute
259 static int ltdb_index_dn_objectclass(struct ldb_module *module,
260 const struct ldb_parse_tree *tree,
261 const struct ldb_message *index_list,
262 struct dn_list *list)
264 struct ldb_context *ldb = module->ldb;
265 unsigned int i;
266 int ret;
267 const char *target = (const char *)tree->u.equality.value.data;
268 const char **subclasses;
270 list->count = 0;
271 list->dn = NULL;
273 ret = ltdb_index_dn_simple(module, tree, index_list, list);
275 subclasses = ldb_subclass_list(module->ldb, target);
277 if (subclasses == NULL) {
278 return ret;
281 for (i=0;subclasses[i];i++) {
282 struct ldb_parse_tree tree2;
283 struct dn_list *list2;
284 tree2.operation = LDB_OP_EQUALITY;
285 tree2.u.equality.attr = LTDB_OBJECTCLASS;
286 if (!tree2.u.equality.attr) {
287 return -1;
289 tree2.u.equality.value.data =
290 (uint8_t *)talloc_strdup(list, subclasses[i]);
291 if (tree2.u.equality.value.data == NULL) {
292 return -1;
294 tree2.u.equality.value.length = strlen(subclasses[i]);
295 list2 = talloc(list, struct dn_list);
296 if (list2 == NULL) {
297 talloc_free(tree2.u.equality.value.data);
298 return -1;
300 if (ltdb_index_dn_objectclass(module, &tree2,
301 index_list, list2) == 1) {
302 if (list->count == 0) {
303 *list = *list2;
304 ret = 1;
305 } else {
306 list_union(ldb, list, list2);
307 talloc_free(list2);
310 talloc_free(tree2.u.equality.value.data);
313 return ret;
317 return a list of dn's that might match a leaf indexed search
319 static int ltdb_index_dn_leaf(struct ldb_module *module,
320 const struct ldb_parse_tree *tree,
321 const struct ldb_message *index_list,
322 struct dn_list *list)
324 if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) {
325 return ltdb_index_dn_objectclass(module, tree, index_list, list);
327 if (ldb_attr_dn(tree->u.equality.attr) == 0) {
328 list->dn = talloc_array(list, char *, 1);
329 if (list->dn == NULL) {
330 ldb_oom(module->ldb);
331 return -1;
333 list->dn[0] = talloc_strdup(list, (char *)tree->u.equality.value.data);
334 if (list->dn[0] == NULL) {
335 ldb_oom(module->ldb);
336 return -1;
338 list->count = 1;
339 return 1;
341 return ltdb_index_dn_simple(module, tree, index_list, list);
346 list intersection
347 list = list & list2
348 relies on the lists being sorted
350 static int list_intersect(struct ldb_context *ldb,
351 struct dn_list *list, const struct dn_list *list2)
353 struct dn_list *list3;
354 unsigned int i;
356 if (list->count == 0 || list2->count == 0) {
357 /* 0 & X == 0 */
358 return 0;
361 list3 = talloc(ldb, struct dn_list);
362 if (list3 == NULL) {
363 return -1;
366 list3->dn = talloc_array(list3, char *, list->count);
367 if (!list3->dn) {
368 talloc_free(list3);
369 return -1;
371 list3->count = 0;
373 for (i=0;i<list->count;i++) {
374 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
375 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
376 list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]);
377 list3->count++;
378 } else {
379 talloc_free(list->dn[i]);
383 talloc_free(list->dn);
384 list->dn = talloc_move(list, &list3->dn);
385 list->count = list3->count;
386 talloc_free(list3);
388 return 0;
393 list union
394 list = list | list2
395 relies on the lists being sorted
397 static int list_union(struct ldb_context *ldb,
398 struct dn_list *list, const struct dn_list *list2)
400 unsigned int i;
401 char **d;
402 unsigned int count = list->count;
404 if (list->count == 0 && list2->count == 0) {
405 /* 0 | 0 == 0 */
406 return 0;
409 d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
410 if (!d) {
411 return -1;
413 list->dn = d;
415 for (i=0;i<list2->count;i++) {
416 if (ldb_list_find(list2->dn[i], list->dn, count,
417 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
418 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
419 if (!list->dn[list->count]) {
420 return -1;
422 list->count++;
426 if (list->count != count) {
427 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
430 return 0;
433 static int ltdb_index_dn(struct ldb_module *module,
434 const struct ldb_parse_tree *tree,
435 const struct ldb_message *index_list,
436 struct dn_list *list);
440 OR two index results
442 static int ltdb_index_dn_or(struct ldb_module *module,
443 const struct ldb_parse_tree *tree,
444 const struct ldb_message *index_list,
445 struct dn_list *list)
447 struct ldb_context *ldb = module->ldb;
448 unsigned int i;
449 int ret;
451 ret = -1;
452 list->dn = NULL;
453 list->count = 0;
455 for (i=0;i<tree->u.list.num_elements;i++) {
456 struct dn_list *list2;
457 int v;
459 list2 = talloc(module, struct dn_list);
460 if (list2 == NULL) {
461 return -1;
464 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
466 if (v == 0) {
467 /* 0 || X == X */
468 if (ret == -1) {
469 ret = 0;
471 talloc_free(list2);
472 continue;
475 if (v == -1) {
476 /* 1 || X == 1 */
477 talloc_free(list->dn);
478 talloc_free(list2);
479 return -1;
482 if (ret == -1) {
483 ret = 1;
484 list->dn = talloc_move(list, &list2->dn);
485 list->count = list2->count;
486 } else {
487 if (list_union(ldb, list, list2) == -1) {
488 talloc_free(list2);
489 return -1;
491 ret = 1;
493 talloc_free(list2);
496 if (list->count == 0) {
497 return 0;
500 return ret;
505 NOT an index results
507 static int ltdb_index_dn_not(struct ldb_module *module,
508 const struct ldb_parse_tree *tree,
509 const struct ldb_message *index_list,
510 struct dn_list *list)
512 /* the only way to do an indexed not would be if we could
513 negate the not via another not or if we knew the total
514 number of database elements so we could know that the
515 existing expression covered the whole database.
517 instead, we just give up, and rely on a full index scan
518 (unless an outer & manages to reduce the list)
520 return -1;
524 AND two index results
526 static int ltdb_index_dn_and(struct ldb_module *module,
527 const struct ldb_parse_tree *tree,
528 const struct ldb_message *index_list,
529 struct dn_list *list)
531 struct ldb_context *ldb = module->ldb;
532 unsigned int i;
533 int ret;
535 ret = -1;
536 list->dn = NULL;
537 list->count = 0;
539 for (i=0;i<tree->u.list.num_elements;i++) {
540 struct dn_list *list2;
541 int v;
543 list2 = talloc(module, struct dn_list);
544 if (list2 == NULL) {
545 return -1;
548 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
550 if (v == 0) {
551 /* 0 && X == 0 */
552 talloc_free(list->dn);
553 talloc_free(list2);
554 return 0;
557 if (v == -1) {
558 talloc_free(list2);
559 continue;
562 if (ret == -1) {
563 ret = 1;
564 talloc_free(list->dn);
565 list->dn = talloc_move(list, &list2->dn);
566 list->count = list2->count;
567 } else {
568 if (list_intersect(ldb, list, list2) == -1) {
569 talloc_free(list2);
570 return -1;
574 talloc_free(list2);
576 if (list->count == 0) {
577 talloc_free(list->dn);
578 return 0;
582 return ret;
586 return a list of dn's that might match a indexed search or
587 -1 if an error. return 0 for no matches, or 1 for matches
589 static int ltdb_index_dn(struct ldb_module *module,
590 const struct ldb_parse_tree *tree,
591 const struct ldb_message *index_list,
592 struct dn_list *list)
594 int ret = -1;
596 switch (tree->operation) {
597 case LDB_OP_AND:
598 ret = ltdb_index_dn_and(module, tree, index_list, list);
599 break;
601 case LDB_OP_OR:
602 ret = ltdb_index_dn_or(module, tree, index_list, list);
603 break;
605 case LDB_OP_NOT:
606 ret = ltdb_index_dn_not(module, tree, index_list, list);
607 break;
609 case LDB_OP_EQUALITY:
610 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
611 break;
613 case LDB_OP_SUBSTRING:
614 case LDB_OP_GREATER:
615 case LDB_OP_LESS:
616 case LDB_OP_PRESENT:
617 case LDB_OP_APPROX:
618 case LDB_OP_EXTENDED:
619 /* we can't index with fancy bitops yet */
620 ret = -1;
621 break;
624 return ret;
628 filter a candidate dn_list from an indexed search into a set of results
629 extracting just the given attributes
631 static int ltdb_index_filter(const struct dn_list *dn_list,
632 struct ldb_handle *handle)
634 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
635 struct ldb_reply *ares = NULL;
636 unsigned int i;
638 for (i = 0; i < dn_list->count; i++) {
639 struct ldb_dn *dn;
640 int ret;
642 ares = talloc_zero(ac, struct ldb_reply);
643 if (!ares) {
644 handle->status = LDB_ERR_OPERATIONS_ERROR;
645 handle->state = LDB_ASYNC_DONE;
646 return LDB_ERR_OPERATIONS_ERROR;
649 ares->message = ldb_msg_new(ares);
650 if (!ares->message) {
651 handle->status = LDB_ERR_OPERATIONS_ERROR;
652 handle->state = LDB_ASYNC_DONE;
653 talloc_free(ares);
654 return LDB_ERR_OPERATIONS_ERROR;
658 dn = ldb_dn_new(ares->message, ac->module->ldb, dn_list->dn[i]);
659 if (dn == NULL) {
660 talloc_free(ares);
661 return LDB_ERR_OPERATIONS_ERROR;
664 ret = ltdb_search_dn1(ac->module, dn, ares->message);
665 talloc_free(dn);
666 if (ret == 0) {
667 /* the record has disappeared? yes, this can happen */
668 talloc_free(ares);
669 continue;
672 if (ret == -1) {
673 /* an internal error */
674 talloc_free(ares);
675 return LDB_ERR_OPERATIONS_ERROR;
678 if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) {
679 talloc_free(ares);
680 continue;
683 /* filter the attributes that the user wants */
684 ret = ltdb_filter_attrs(ares->message, ac->attrs);
686 if (ret == -1) {
687 handle->status = LDB_ERR_OPERATIONS_ERROR;
688 handle->state = LDB_ASYNC_DONE;
689 talloc_free(ares);
690 return LDB_ERR_OPERATIONS_ERROR;
693 ares->type = LDB_REPLY_ENTRY;
694 handle->state = LDB_ASYNC_PENDING;
695 handle->status = ac->callback(ac->module->ldb, ac->context, ares);
697 if (handle->status != LDB_SUCCESS) {
698 handle->state = LDB_ASYNC_DONE;
699 return handle->status;
703 return LDB_SUCCESS;
707 search the database with a LDAP-like expression using indexes
708 returns -1 if an indexed search is not possible, in which
709 case the caller should call ltdb_search_full()
711 int ltdb_search_indexed(struct ldb_handle *handle)
713 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
714 struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
715 struct dn_list *dn_list;
716 int ret;
718 if (ltdb->cache->indexlist->num_elements == 0 &&
719 ac->scope != LDB_SCOPE_BASE) {
720 /* no index list? must do full search */
721 return -1;
724 dn_list = talloc(handle, struct dn_list);
725 if (dn_list == NULL) {
726 return -1;
729 if (ac->scope == LDB_SCOPE_BASE) {
730 /* with BASE searches only one DN can match */
731 dn_list->dn = talloc_array(dn_list, char *, 1);
732 if (dn_list->dn == NULL) {
733 ldb_oom(ac->module->ldb);
734 return -1;
736 dn_list->dn[0] = ldb_dn_alloc_linearized(dn_list, ac->base);
737 if (dn_list->dn[0] == NULL) {
738 ldb_oom(ac->module->ldb);
739 return -1;
741 dn_list->count = 1;
742 ret = 1;
743 } else {
744 ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list);
747 if (ret == 1) {
748 /* we've got a candidate list - now filter by the full tree
749 and extract the needed attributes */
750 ret = ltdb_index_filter(dn_list, handle);
751 handle->status = ret;
752 handle->state = LDB_ASYNC_DONE;
755 talloc_free(dn_list);
757 return ret;
761 add a index element where this is the first indexed DN for this value
763 static int ltdb_index_add1_new(struct ldb_context *ldb,
764 struct ldb_message *msg,
765 struct ldb_message_element *el,
766 const char *dn)
768 struct ldb_message_element *el2;
770 /* add another entry */
771 el2 = talloc_realloc(msg, msg->elements,
772 struct ldb_message_element, msg->num_elements+1);
773 if (!el2) {
774 return -1;
777 msg->elements = el2;
778 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
779 if (!msg->elements[msg->num_elements].name) {
780 return -1;
782 msg->elements[msg->num_elements].num_values = 0;
783 msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
784 if (!msg->elements[msg->num_elements].values) {
785 return -1;
787 msg->elements[msg->num_elements].values[0].length = strlen(dn);
788 msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn);
789 msg->elements[msg->num_elements].num_values = 1;
790 msg->num_elements++;
792 return 0;
797 add a index element where this is not the first indexed DN for this
798 value
800 static int ltdb_index_add1_add(struct ldb_context *ldb,
801 struct ldb_message *msg,
802 struct ldb_message_element *el,
803 int idx,
804 const char *dn)
806 struct ldb_val *v2;
807 unsigned int i;
809 /* for multi-valued attributes we can end up with repeats */
810 for (i=0;i<msg->elements[idx].num_values;i++) {
811 if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) {
812 return 0;
816 v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
817 struct ldb_val,
818 msg->elements[idx].num_values+1);
819 if (!v2) {
820 return -1;
822 msg->elements[idx].values = v2;
824 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
825 msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn);
826 msg->elements[idx].num_values++;
828 return 0;
832 add an index entry for one message element
834 static int ltdb_index_add1(struct ldb_module *module, const char *dn,
835 struct ldb_message_element *el, int v_idx)
837 struct ldb_context *ldb = module->ldb;
838 struct ldb_message *msg;
839 struct ldb_dn *dn_key;
840 int ret;
841 unsigned int i;
843 msg = talloc(module, struct ldb_message);
844 if (msg == NULL) {
845 errno = ENOMEM;
846 return -1;
849 dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]);
850 if (!dn_key) {
851 talloc_free(msg);
852 return -1;
854 talloc_steal(msg, dn_key);
856 ret = ltdb_search_dn1(module, dn_key, msg);
857 if (ret == -1) {
858 talloc_free(msg);
859 return -1;
862 if (ret == 0) {
863 msg->dn = dn_key;
864 msg->num_elements = 0;
865 msg->elements = NULL;
868 for (i=0;i<msg->num_elements;i++) {
869 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
870 break;
874 if (i == msg->num_elements) {
875 ret = ltdb_index_add1_new(ldb, msg, el, dn);
876 } else {
877 ret = ltdb_index_add1_add(ldb, msg, el, i, dn);
880 if (ret == 0) {
881 ret = ltdb_store(module, msg, TDB_REPLACE);
884 talloc_free(msg);
886 return ret;
889 static int ltdb_index_add0(struct ldb_module *module, const char *dn,
890 struct ldb_message_element *elements, int num_el)
892 struct ltdb_private *ltdb = module->private_data;
893 int ret;
894 unsigned int i, j;
896 if (dn[0] == '@') {
897 return 0;
900 if (ltdb->cache->indexlist->num_elements == 0) {
901 /* no indexed fields */
902 return 0;
905 for (i = 0; i < num_el; i++) {
906 ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name,
907 NULL, LTDB_IDXATTR);
908 if (ret == -1) {
909 continue;
911 for (j = 0; j < elements[i].num_values; j++) {
912 ret = ltdb_index_add1(module, dn, &elements[i], j);
913 if (ret == -1) {
914 return -1;
919 return 0;
923 add the index entries for a new record
924 return -1 on failure
926 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
928 const char *dn;
929 int ret;
931 dn = ldb_dn_get_linearized(msg->dn);
932 if (dn == NULL) {
933 return -1;
936 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
938 return ret;
943 delete an index entry for one message element
945 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
946 struct ldb_message_element *el, int v_idx)
948 struct ldb_context *ldb = module->ldb;
949 struct ldb_message *msg;
950 struct ldb_dn *dn_key;
951 int ret, i;
952 unsigned int j;
954 if (dn[0] == '@') {
955 return 0;
958 dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]);
959 if (!dn_key) {
960 return -1;
963 msg = talloc(dn_key, struct ldb_message);
964 if (msg == NULL) {
965 talloc_free(dn_key);
966 return -1;
969 ret = ltdb_search_dn1(module, dn_key, msg);
970 if (ret == -1) {
971 talloc_free(dn_key);
972 return -1;
975 if (ret == 0) {
976 /* it wasn't indexed. Did we have an earlier error? If we did then
977 its gone now */
978 talloc_free(dn_key);
979 return 0;
982 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
983 if (i == -1) {
984 ldb_debug(ldb, LDB_DEBUG_ERROR,
985 "ERROR: dn %s not found in %s\n", dn,
986 ldb_dn_get_linearized(dn_key));
987 /* it ain't there. hmmm */
988 talloc_free(dn_key);
989 return 0;
992 if (j != msg->elements[i].num_values - 1) {
993 memmove(&msg->elements[i].values[j],
994 &msg->elements[i].values[j+1],
995 (msg->elements[i].num_values-(j+1)) *
996 sizeof(msg->elements[i].values[0]));
998 msg->elements[i].num_values--;
1000 if (msg->elements[i].num_values == 0) {
1001 ret = ltdb_delete_noindex(module, dn_key);
1002 } else {
1003 ret = ltdb_store(module, msg, TDB_REPLACE);
1006 talloc_free(dn_key);
1008 return ret;
1012 delete the index entries for a record
1013 return -1 on failure
1015 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
1017 struct ltdb_private *ltdb = module->private_data;
1018 int ret;
1019 const char *dn;
1020 unsigned int i, j;
1022 /* find the list of indexed fields */
1023 if (ltdb->cache->indexlist->num_elements == 0) {
1024 /* no indexed fields */
1025 return 0;
1028 if (ldb_dn_is_special(msg->dn)) {
1029 return 0;
1032 dn = ldb_dn_get_linearized(msg->dn);
1033 if (dn == NULL) {
1034 return -1;
1037 for (i = 0; i < msg->num_elements; i++) {
1038 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
1039 NULL, LTDB_IDXATTR);
1040 if (ret == -1) {
1041 continue;
1043 for (j = 0; j < msg->elements[i].num_values; j++) {
1044 ret = ltdb_index_del_value(module, dn, &msg->elements[i], j);
1045 if (ret == -1) {
1046 return -1;
1051 return 0;
1056 traversal function that deletes all @INDEX records
1058 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
1060 const char *dn = "DN=" LTDB_INDEX ":";
1061 if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) {
1062 return tdb_delete(tdb, key);
1064 return 0;
1068 traversal function that adds @INDEX records during a re index
1070 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
1072 struct ldb_module *module = state;
1073 struct ldb_message *msg;
1074 const char *dn = NULL;
1075 int ret;
1076 TDB_DATA key2;
1078 if (strncmp((char *)key.dptr, "DN=@", 4) == 0 ||
1079 strncmp((char *)key.dptr, "DN=", 3) != 0) {
1080 return 0;
1083 msg = talloc(module, struct ldb_message);
1084 if (msg == NULL) {
1085 return -1;
1088 ret = ltdb_unpack_data(module, &data, msg);
1089 if (ret != 0) {
1090 talloc_free(msg);
1091 return -1;
1094 /* check if the DN key has changed, perhaps due to the
1095 case insensitivity of an element changing */
1096 key2 = ltdb_key(module, msg->dn);
1097 if (key2.dptr == NULL) {
1098 /* probably a corrupt record ... darn */
1099 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n",
1100 ldb_dn_get_linearized(msg->dn));
1101 talloc_free(msg);
1102 return 0;
1104 if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
1105 tdb_delete(tdb, key);
1106 tdb_store(tdb, key2, data, 0);
1108 talloc_free(key2.dptr);
1110 if (msg->dn == NULL) {
1111 dn = (char *)key.dptr + 3;
1112 } else {
1113 dn = ldb_dn_get_linearized(msg->dn);
1116 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
1118 talloc_free(msg);
1120 return ret;
1124 force a complete reindex of the database
1126 int ltdb_reindex(struct ldb_module *module)
1128 struct ltdb_private *ltdb = module->private_data;
1129 int ret;
1131 if (ltdb_cache_reload(module) != 0) {
1132 return -1;
1135 /* first traverse the database deleting any @INDEX records */
1136 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
1137 if (ret == -1) {
1138 return -1;
1141 /* now traverse adding any indexes for normal LDB records */
1142 ret = tdb_traverse(ltdb->tdb, re_index, module);
1143 if (ret == -1) {
1144 return -1;
1147 return 0;