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 3 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, see <http://www.gnu.org/licenses/>.
27 * Component: ldb tdb backend - indexing
29 * Description: indexing routines for ldb tdb backend
31 * Author: Andrew Tridgell
34 #include "ldb_includes.h"
39 find an element in a list, using the given comparison function and
40 assuming that the list is already sorted using comp_fn
42 return -1 if not found, or the index of the first occurance of needle if found
44 static int ldb_list_find(const void *needle,
45 const void *base, size_t nmemb, size_t size,
46 comparison_fn_t comp_fn)
48 const char *base_p = (const char *)base;
49 size_t min_i, max_i, test_i;
58 while (min_i < max_i) {
61 test_i = (min_i + max_i) / 2;
62 /* the following cast looks strange, but is
63 correct. The key to understanding it is that base_p
64 is a pointer to an array of pointers, so we have to
65 dereference it after casting to void **. The strange
66 const in the middle gives us the right type of pointer
67 after the dereference (tridge) */
68 r = comp_fn(needle, *(void * const *)(base_p + (size * test_i)));
70 /* scan back for first element */
72 comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) {
88 if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) {
101 return the dn key to be used for an index
104 static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb,
105 const char *attr, const struct ldb_val *value)
109 const struct ldb_schema_attribute *a;
113 attr_folded = ldb_attr_casefold(ldb, attr);
118 a = ldb_schema_attribute_by_name(ldb, attr);
119 r = a->syntax->canonicalise_fn(ldb, ldb, value, &v);
120 if (r != LDB_SUCCESS) {
121 const char *errstr = ldb_errstring(ldb);
122 /* canonicalisation can be refused. For example,
123 a attribute that takes wildcards will refuse to canonicalise
124 if the value contains a wildcard */
125 ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s%s%s",
126 attr, ldb_strerror(r), (errstr?":":""), (errstr?errstr:""));
127 talloc_free(attr_folded);
130 if (ldb_should_b64_encode(&v)) {
131 char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length);
132 if (!vstr) return NULL;
133 ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr);
136 ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data);
139 if (v.data != value->data) {
142 talloc_free(attr_folded);
148 see if a attribute value is in the list of indexed attributes
150 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
151 unsigned int *v_idx, const char *key)
154 for (i=0;i<msg->num_elements;i++) {
155 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
156 const struct ldb_message_element *el = &msg->elements[i];
159 /* in this case we are just looking to see if key is present,
160 we are not spearching for a specific index */
164 for (j=0;j<el->num_values;j++) {
165 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
177 /* used in sorting dn lists */
178 static int list_cmp(const char **s1, const char **s2)
180 return strcmp(*s1, *s2);
184 return a list of dn's that might match a simple indexed search or
186 static int ltdb_index_dn_simple(struct ldb_module *module,
187 const struct ldb_parse_tree *tree,
188 const struct ldb_message *index_list,
189 struct dn_list *list)
191 struct ldb_context *ldb = module->ldb;
195 struct ldb_message *msg;
200 /* if the attribute isn't in the list of indexed attributes then
201 this node needs a full search */
202 if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) {
203 return LDB_ERR_OPERATIONS_ERROR;
206 /* the attribute is indexed. Pull the list of DNs that match the
208 dn = ltdb_index_key(ldb, tree->u.equality.attr, &tree->u.equality.value);
209 if (!dn) return LDB_ERR_OPERATIONS_ERROR;
211 msg = talloc(list, struct ldb_message);
213 return LDB_ERR_OPERATIONS_ERROR;
216 ret = ltdb_search_dn1(module, dn, msg);
218 if (ret != LDB_SUCCESS) {
222 for (i=0;i<msg->num_elements;i++) {
223 struct ldb_message_element *el;
225 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
229 el = &msg->elements[i];
231 list->dn = talloc_array(list, char *, el->num_values);
234 return LDB_ERR_OPERATIONS_ERROR;
237 for (j=0;j<el->num_values;j++) {
238 list->dn[list->count] =
239 talloc_strdup(list->dn, (char *)el->values[j].data);
240 if (!list->dn[list->count]) {
242 return LDB_ERR_OPERATIONS_ERROR;
250 if (list->count > 1) {
251 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
258 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
261 return a list of dn's that might match a simple indexed search on
262 the special objectclass attribute
264 static int ltdb_index_dn_objectclass(struct ldb_module *module,
265 const struct ldb_parse_tree *tree,
266 const struct ldb_message *index_list,
267 struct dn_list *list)
269 struct ldb_context *ldb = module->ldb;
272 const char *target = (const char *)tree->u.equality.value.data;
273 const char **subclasses;
278 ret = ltdb_index_dn_simple(module, tree, index_list, list);
280 subclasses = ldb_subclass_list(module->ldb, target);
282 if (subclasses == NULL) {
286 for (i=0;subclasses[i];i++) {
287 struct ldb_parse_tree tree2;
288 struct dn_list *list2;
289 tree2.operation = LDB_OP_EQUALITY;
290 tree2.u.equality.attr = LTDB_OBJECTCLASS;
291 if (!tree2.u.equality.attr) {
292 return LDB_ERR_OPERATIONS_ERROR;
294 tree2.u.equality.value.data =
295 (uint8_t *)talloc_strdup(list, subclasses[i]);
296 if (tree2.u.equality.value.data == NULL) {
297 return LDB_ERR_OPERATIONS_ERROR;
299 tree2.u.equality.value.length = strlen(subclasses[i]);
300 list2 = talloc(list, struct dn_list);
302 talloc_free(tree2.u.equality.value.data);
303 return LDB_ERR_OPERATIONS_ERROR;
305 if (ltdb_index_dn_objectclass(module, &tree2,
306 index_list, list2) == LDB_SUCCESS) {
307 if (list->count == 0) {
311 list_union(ldb, list, list2);
315 talloc_free(tree2.u.equality.value.data);
322 return a list of dn's that might match a leaf indexed search
324 static int ltdb_index_dn_leaf(struct ldb_module *module,
325 const struct ldb_parse_tree *tree,
326 const struct ldb_message *index_list,
327 struct dn_list *list)
329 if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) {
330 return ltdb_index_dn_objectclass(module, tree, index_list, list);
332 if (ldb_attr_dn(tree->u.equality.attr) == 0) {
333 list->dn = talloc_array(list, char *, 1);
334 if (list->dn == NULL) {
335 ldb_oom(module->ldb);
336 return LDB_ERR_OPERATIONS_ERROR;
338 list->dn[0] = talloc_strdup(list->dn, (char *)tree->u.equality.value.data);
339 if (list->dn[0] == NULL) {
340 ldb_oom(module->ldb);
341 return LDB_ERR_OPERATIONS_ERROR;
346 return ltdb_index_dn_simple(module, tree, index_list, list);
353 relies on the lists being sorted
355 static int list_intersect(struct ldb_context *ldb,
356 struct dn_list *list, const struct dn_list *list2)
358 struct dn_list *list3;
361 if (list->count == 0 || list2->count == 0) {
363 return LDB_ERR_NO_SUCH_OBJECT;
366 list3 = talloc(ldb, struct dn_list);
368 return LDB_ERR_OPERATIONS_ERROR;
371 list3->dn = talloc_array(list3, char *, list->count);
374 return LDB_ERR_OPERATIONS_ERROR;
378 for (i=0;i<list->count;i++) {
379 if (ldb_list_find(list->dn[i], list2->dn, list2->count,
380 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
381 list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]);
384 talloc_free(list->dn[i]);
388 talloc_free(list->dn);
389 list->dn = talloc_move(list, &list3->dn);
390 list->count = list3->count;
393 return LDB_ERR_NO_SUCH_OBJECT;
400 relies on the lists being sorted
402 static int list_union(struct ldb_context *ldb,
403 struct dn_list *list, const struct dn_list *list2)
407 unsigned int count = list->count;
409 if (list->count == 0 && list2->count == 0) {
411 return LDB_ERR_NO_SUCH_OBJECT;
414 d = talloc_realloc(list, list->dn, char *, list->count + list2->count);
416 return LDB_ERR_OPERATIONS_ERROR;
420 for (i=0;i<list2->count;i++) {
421 if (ldb_list_find(list2->dn[i], list->dn, count,
422 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
423 list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]);
424 if (!list->dn[list->count]) {
425 return LDB_ERR_OPERATIONS_ERROR;
431 if (list->count != count) {
432 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
435 return LDB_ERR_NO_SUCH_OBJECT;
438 static int ltdb_index_dn(struct ldb_module *module,
439 const struct ldb_parse_tree *tree,
440 const struct ldb_message *index_list,
441 struct dn_list *list);
447 static int ltdb_index_dn_or(struct ldb_module *module,
448 const struct ldb_parse_tree *tree,
449 const struct ldb_message *index_list,
450 struct dn_list *list)
452 struct ldb_context *ldb = module->ldb;
456 ret = LDB_ERR_OPERATIONS_ERROR;
460 for (i=0;i<tree->u.list.num_elements;i++) {
461 struct dn_list *list2;
464 list2 = talloc(module, struct dn_list);
466 return LDB_ERR_OPERATIONS_ERROR;
469 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
471 if (v == LDB_ERR_NO_SUCH_OBJECT) {
473 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
480 if (v != LDB_SUCCESS && v != LDB_ERR_NO_SUCH_OBJECT) {
482 talloc_free(list->dn);
487 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
489 list->dn = talloc_move(list, &list2->dn);
490 list->count = list2->count;
492 if (list_union(ldb, list, list2) == -1) {
494 return LDB_ERR_OPERATIONS_ERROR;
501 if (list->count == 0) {
502 return LDB_ERR_NO_SUCH_OBJECT;
512 static int ltdb_index_dn_not(struct ldb_module *module,
513 const struct ldb_parse_tree *tree,
514 const struct ldb_message *index_list,
515 struct dn_list *list)
517 /* the only way to do an indexed not would be if we could
518 negate the not via another not or if we knew the total
519 number of database elements so we could know that the
520 existing expression covered the whole database.
522 instead, we just give up, and rely on a full index scan
523 (unless an outer & manages to reduce the list)
525 return LDB_ERR_OPERATIONS_ERROR;
529 AND two index results
531 static int ltdb_index_dn_and(struct ldb_module *module,
532 const struct ldb_parse_tree *tree,
533 const struct ldb_message *index_list,
534 struct dn_list *list)
536 struct ldb_context *ldb = module->ldb;
540 ret = LDB_ERR_OPERATIONS_ERROR;
544 for (i=0;i<tree->u.list.num_elements;i++) {
545 struct dn_list *list2;
548 list2 = talloc(module, struct dn_list);
550 return LDB_ERR_OPERATIONS_ERROR;
553 v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2);
555 if (v == LDB_ERR_NO_SUCH_OBJECT) {
557 talloc_free(list->dn);
559 return LDB_ERR_NO_SUCH_OBJECT;
562 if (v != LDB_SUCCESS && v != LDB_ERR_NO_SUCH_OBJECT) {
567 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
569 talloc_free(list->dn);
570 list->dn = talloc_move(list, &list2->dn);
571 list->count = list2->count;
573 if (list_intersect(ldb, list, list2) == -1) {
575 return LDB_ERR_OPERATIONS_ERROR;
581 if (list->count == 0) {
582 talloc_free(list->dn);
583 return LDB_ERR_NO_SUCH_OBJECT;
591 AND index results and ONE level special index
593 static int ltdb_index_dn_one(struct ldb_module *module,
594 struct ldb_dn *parent_dn,
595 struct dn_list *list)
597 struct ldb_context *ldb = module->ldb;
598 struct dn_list *list2;
599 struct ldb_message *msg;
605 list2 = talloc_zero(module, struct dn_list);
607 return LDB_ERR_OPERATIONS_ERROR;
610 /* the attribute is indexed. Pull the list of DNs that match the
612 val.data = (uint8_t *)((intptr_t)ldb_dn_get_casefold(parent_dn));
613 val.length = strlen((char *)val.data);
614 key = ltdb_index_key(ldb, LTDB_IDXONE, &val);
617 return LDB_ERR_OPERATIONS_ERROR;
620 msg = talloc(list2, struct ldb_message);
623 return LDB_ERR_OPERATIONS_ERROR;
626 ret = ltdb_search_dn1(module, key, msg);
628 if (ret != LDB_SUCCESS) {
632 for (i = 0; i < msg->num_elements; i++) {
633 struct ldb_message_element *el;
635 if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) {
639 el = &msg->elements[i];
641 list2->dn = talloc_array(list2, char *, el->num_values);
644 return LDB_ERR_OPERATIONS_ERROR;
647 for (j = 0; j < el->num_values; j++) {
648 list2->dn[list2->count] = talloc_strdup(list2->dn, (char *)el->values[j].data);
649 if (!list2->dn[list2->count]) {
651 return LDB_ERR_OPERATIONS_ERROR;
657 if (list2->count == 0) {
659 return LDB_ERR_NO_SUCH_OBJECT;
662 if (list2->count > 1) {
663 qsort(list2->dn, list2->count, sizeof(char *), (comparison_fn_t) list_cmp);
666 if (list->count > 0) {
667 if (list_intersect(ldb, list, list2) == -1) {
669 return LDB_ERR_OPERATIONS_ERROR;
672 if (list->count == 0) {
673 talloc_free(list->dn);
675 return LDB_ERR_NO_SUCH_OBJECT;
678 list->dn = talloc_move(list, &list2->dn);
679 list->count = list2->count;
688 return a list of dn's that might match a indexed search or
689 an error. return LDB_ERR_NO_SUCH_OBJECT for no matches, or LDB_SUCCESS for matches
691 static int ltdb_index_dn(struct ldb_module *module,
692 const struct ldb_parse_tree *tree,
693 const struct ldb_message *index_list,
694 struct dn_list *list)
696 int ret = LDB_ERR_OPERATIONS_ERROR;
698 switch (tree->operation) {
700 ret = ltdb_index_dn_and(module, tree, index_list, list);
704 ret = ltdb_index_dn_or(module, tree, index_list, list);
708 ret = ltdb_index_dn_not(module, tree, index_list, list);
711 case LDB_OP_EQUALITY:
712 ret = ltdb_index_dn_leaf(module, tree, index_list, list);
715 case LDB_OP_SUBSTRING:
720 case LDB_OP_EXTENDED:
721 /* we can't index with fancy bitops yet */
722 ret = LDB_ERR_OPERATIONS_ERROR;
730 filter a candidate dn_list from an indexed search into a set of results
731 extracting just the given attributes
733 static int ltdb_index_filter(const struct dn_list *dn_list,
734 struct ldb_handle *handle)
736 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
737 struct ldb_reply *ares = NULL;
740 for (i = 0; i < dn_list->count; i++) {
744 ares = talloc_zero(ac, struct ldb_reply);
746 handle->status = LDB_ERR_OPERATIONS_ERROR;
747 handle->state = LDB_ASYNC_DONE;
748 return LDB_ERR_OPERATIONS_ERROR;
751 ares->message = ldb_msg_new(ares);
752 if (!ares->message) {
753 handle->status = LDB_ERR_OPERATIONS_ERROR;
754 handle->state = LDB_ASYNC_DONE;
756 return LDB_ERR_OPERATIONS_ERROR;
760 dn = ldb_dn_new(ares->message, ac->module->ldb, dn_list->dn[i]);
763 return LDB_ERR_OPERATIONS_ERROR;
766 ret = ltdb_search_dn1(ac->module, dn, ares->message);
768 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
769 /* the record has disappeared? yes, this can happen */
774 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
775 /* an internal error */
777 return LDB_ERR_OPERATIONS_ERROR;
780 if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) {
785 /* filter the attributes that the user wants */
786 ret = ltdb_filter_attrs(ares->message, ac->attrs);
789 handle->status = LDB_ERR_OPERATIONS_ERROR;
790 handle->state = LDB_ASYNC_DONE;
792 return LDB_ERR_OPERATIONS_ERROR;
795 ares->type = LDB_REPLY_ENTRY;
796 handle->state = LDB_ASYNC_PENDING;
797 handle->status = ac->callback(ac->module->ldb, ac->context, ares);
799 if (handle->status != LDB_SUCCESS) {
800 handle->state = LDB_ASYNC_DONE;
801 return handle->status;
809 search the database with a LDAP-like expression using indexes
810 returns -1 if an indexed search is not possible, in which
811 case the caller should call ltdb_search_full()
813 int ltdb_search_indexed(struct ldb_handle *handle)
815 struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
816 struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
817 struct dn_list *dn_list;
818 int ret, idxattr, idxone;
820 idxattr = idxone = 0;
821 ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXATTR);
826 /* We do one level indexing only if requested */
827 ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXONE);
832 if ((ac->scope == LDB_SCOPE_ONELEVEL && (idxattr+idxone == 0)) ||
833 (ac->scope == LDB_SCOPE_SUBTREE && idxattr == 0)) {
834 /* no indexs? must do full search */
835 return LDB_ERR_OPERATIONS_ERROR;
838 ret = LDB_ERR_OPERATIONS_ERROR;
840 dn_list = talloc_zero(handle, struct dn_list);
841 if (dn_list == NULL) {
842 return LDB_ERR_OPERATIONS_ERROR;
845 if (ac->scope == LDB_SCOPE_BASE) {
846 /* with BASE searches only one DN can match */
847 dn_list->dn = talloc_array(dn_list, char *, 1);
848 if (dn_list->dn == NULL) {
849 ldb_oom(ac->module->ldb);
850 return LDB_ERR_OPERATIONS_ERROR;
852 dn_list->dn[0] = ldb_dn_alloc_linearized(dn_list, ac->base);
853 if (dn_list->dn[0] == NULL) {
854 ldb_oom(ac->module->ldb);
855 return LDB_ERR_OPERATIONS_ERROR;
861 if (ac->scope != LDB_SCOPE_BASE && idxattr == 1) {
862 ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list);
864 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
865 talloc_free(dn_list);
870 if (ac->scope == LDB_SCOPE_ONELEVEL && idxone == 1) {
871 ret = ltdb_index_dn_one(ac->module, ac->base, dn_list);
874 if (ret == LDB_SUCCESS) {
875 /* we've got a candidate list - now filter by the full tree
876 and extract the needed attributes */
877 ret = ltdb_index_filter(dn_list, handle);
878 handle->status = ret;
879 handle->state = LDB_ASYNC_DONE;
882 talloc_free(dn_list);
888 add a index element where this is the first indexed DN for this value
890 static int ltdb_index_add1_new(struct ldb_context *ldb,
891 struct ldb_message *msg,
894 struct ldb_message_element *el;
896 /* add another entry */
897 el = talloc_realloc(msg, msg->elements,
898 struct ldb_message_element, msg->num_elements+1);
900 return LDB_ERR_OPERATIONS_ERROR;
904 msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX);
905 if (!msg->elements[msg->num_elements].name) {
906 return LDB_ERR_OPERATIONS_ERROR;
908 msg->elements[msg->num_elements].num_values = 0;
909 msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val);
910 if (!msg->elements[msg->num_elements].values) {
911 return LDB_ERR_OPERATIONS_ERROR;
913 msg->elements[msg->num_elements].values[0].length = strlen(dn);
914 msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn);
915 msg->elements[msg->num_elements].num_values = 1;
923 add a index element where this is not the first indexed DN for this
926 static int ltdb_index_add1_add(struct ldb_context *ldb,
927 struct ldb_message *msg,
934 /* for multi-valued attributes we can end up with repeats */
935 for (i=0;i<msg->elements[idx].num_values;i++) {
936 if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) {
941 v2 = talloc_realloc(msg->elements, msg->elements[idx].values,
943 msg->elements[idx].num_values+1);
945 return LDB_ERR_OPERATIONS_ERROR;
947 msg->elements[idx].values = v2;
949 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
950 msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn);
951 msg->elements[idx].num_values++;
957 add an index entry for one message element
959 static int ltdb_index_add1(struct ldb_module *module, const char *dn,
960 struct ldb_message_element *el, int v_idx)
962 struct ldb_context *ldb = module->ldb;
963 struct ldb_message *msg;
964 struct ldb_dn *dn_key;
968 msg = talloc(module, struct ldb_message);
971 return LDB_ERR_OPERATIONS_ERROR;
974 dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]);
977 return LDB_ERR_OPERATIONS_ERROR;
979 talloc_steal(msg, dn_key);
981 ret = ltdb_search_dn1(module, dn_key, msg);
982 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
987 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
989 msg->num_elements = 0;
990 msg->elements = NULL;
993 for (i=0;i<msg->num_elements;i++) {
994 if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) {
999 if (i == msg->num_elements) {
1000 ret = ltdb_index_add1_new(ldb, msg, dn);
1002 ret = ltdb_index_add1_add(ldb, msg, i, dn);
1005 if (ret == LDB_SUCCESS) {
1006 ret = ltdb_store(module, msg, TDB_REPLACE);
1014 static int ltdb_index_add0(struct ldb_module *module, const char *dn,
1015 struct ldb_message_element *elements, int num_el)
1017 struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
1025 if (ltdb->cache->indexlist->num_elements == 0) {
1026 /* no indexed fields */
1030 for (i = 0; i < num_el; i++) {
1031 ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name,
1032 NULL, LTDB_IDXATTR);
1036 for (j = 0; j < elements[i].num_values; j++) {
1037 ret = ltdb_index_add1(module, dn, &elements[i], j);
1038 if (ret != LDB_SUCCESS) {
1048 add the index entries for a new record
1050 int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg)
1055 dn = ldb_dn_get_linearized(msg->dn);
1057 return LDB_ERR_OPERATIONS_ERROR;
1060 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
1067 delete an index entry for one message element
1069 int ltdb_index_del_value(struct ldb_module *module, const char *dn,
1070 struct ldb_message_element *el, int v_idx)
1072 struct ldb_context *ldb = module->ldb;
1073 struct ldb_message *msg;
1074 struct ldb_dn *dn_key;
1082 dn_key = ltdb_index_key(ldb, el->name, &el->values[v_idx]);
1084 return LDB_ERR_OPERATIONS_ERROR;
1087 msg = talloc(dn_key, struct ldb_message);
1089 talloc_free(dn_key);
1090 return LDB_ERR_OPERATIONS_ERROR;
1093 ret = ltdb_search_dn1(module, dn_key, msg);
1094 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
1095 talloc_free(dn_key);
1099 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1100 /* it wasn't indexed. Did we have an earlier error? If we did then
1102 talloc_free(dn_key);
1106 i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX);
1108 ldb_debug(ldb, LDB_DEBUG_ERROR,
1109 "ERROR: dn %s not found in %s\n", dn,
1110 ldb_dn_get_linearized(dn_key));
1111 /* it ain't there. hmmm */
1112 talloc_free(dn_key);
1116 if (j != msg->elements[i].num_values - 1) {
1117 memmove(&msg->elements[i].values[j],
1118 &msg->elements[i].values[j+1],
1119 (msg->elements[i].num_values-(j+1)) *
1120 sizeof(msg->elements[i].values[0]));
1122 msg->elements[i].num_values--;
1124 if (msg->elements[i].num_values == 0) {
1125 ret = ltdb_delete_noindex(module, dn_key);
1127 ret = ltdb_store(module, msg, TDB_REPLACE);
1130 talloc_free(dn_key);
1136 delete the index entries for a record
1137 return -1 on failure
1139 int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg)
1141 struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
1146 /* find the list of indexed fields */
1147 if (ltdb->cache->indexlist->num_elements == 0) {
1148 /* no indexed fields */
1152 if (ldb_dn_is_special(msg->dn)) {
1156 dn = ldb_dn_get_linearized(msg->dn);
1158 return LDB_ERR_OPERATIONS_ERROR;
1161 for (i = 0; i < msg->num_elements; i++) {
1162 ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name,
1163 NULL, LTDB_IDXATTR);
1167 for (j = 0; j < msg->elements[i].num_values; j++) {
1168 ret = ltdb_index_del_value(module, dn, &msg->elements[i], j);
1169 if (ret != LDB_SUCCESS) {
1179 handle special index for one level searches
1181 int ltdb_index_one(struct ldb_module *module, const struct ldb_message *msg, int add)
1183 struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
1184 struct ldb_message_element el;
1190 /* We index for ONE Level only if requested */
1191 ret = ldb_msg_find_idx(ltdb->cache->indexlist, NULL, NULL, LTDB_IDXONE);
1196 pdn = ldb_dn_get_parent(module, msg->dn);
1198 return LDB_ERR_OPERATIONS_ERROR;
1201 dn = ldb_dn_get_linearized(msg->dn);
1204 return LDB_ERR_OPERATIONS_ERROR;
1207 val.data = (uint8_t *)((intptr_t)ldb_dn_get_casefold(pdn));
1208 if (val.data == NULL) {
1210 return LDB_ERR_OPERATIONS_ERROR;
1213 val.length = strlen((char *)val.data);
1214 el.name = LTDB_IDXONE;
1219 ret = ltdb_index_add1(module, dn, &el, 0);
1220 } else { /* delete */
1221 ret = ltdb_index_del_value(module, dn, &el, 0);
1231 traversal function that deletes all @INDEX records
1233 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
1235 const char *dn = "DN=" LTDB_INDEX ":";
1236 if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) {
1237 return tdb_delete(tdb, key);
1243 traversal function that adds @INDEX records during a re index
1245 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
1247 struct ldb_module *module = (struct ldb_module *)state;
1248 struct ldb_message *msg;
1249 const char *dn = NULL;
1253 if (strncmp((char *)key.dptr, "DN=@", 4) == 0 ||
1254 strncmp((char *)key.dptr, "DN=", 3) != 0) {
1258 msg = talloc(module, struct ldb_message);
1263 ret = ltdb_unpack_data(module, &data, msg);
1269 /* check if the DN key has changed, perhaps due to the
1270 case insensitivity of an element changing */
1271 key2 = ltdb_key(module, msg->dn);
1272 if (key2.dptr == NULL) {
1273 /* probably a corrupt record ... darn */
1274 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n",
1275 ldb_dn_get_linearized(msg->dn));
1279 if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) {
1280 tdb_delete(tdb, key);
1281 tdb_store(tdb, key2, data, 0);
1283 talloc_free(key2.dptr);
1285 if (msg->dn == NULL) {
1286 dn = (char *)key.dptr + 3;
1288 dn = ldb_dn_get_linearized(msg->dn);
1291 ret = ltdb_index_one(module, msg, 1);
1292 if (ret == LDB_SUCCESS) {
1293 ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements);
1295 ldb_debug(module->ldb, LDB_DEBUG_ERROR,
1296 "Adding special ONE LEVEL index failed (%s)!\n",
1297 ldb_dn_get_linearized(msg->dn));
1302 if (ret != LDB_SUCCESS) return -1;
1308 force a complete reindex of the database
1310 int ltdb_reindex(struct ldb_module *module)
1312 struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
1315 if (ltdb_cache_reload(module) != 0) {
1316 return LDB_ERR_OPERATIONS_ERROR;
1319 /* first traverse the database deleting any @INDEX records */
1320 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
1322 return LDB_ERR_OPERATIONS_ERROR;
1325 /* if we don't have indexes we have nothing todo */
1326 if (ltdb->cache->indexlist->num_elements == 0) {
1330 /* now traverse adding any indexes for normal LDB records */
1331 ret = tdb_traverse(ltdb->tdb, re_index, module);
1333 return LDB_ERR_OPERATIONS_ERROR;