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/ldb_tdb/ldb_tdb.h"
37 #include "ldb/include/ldb_parse.h"
47 static void dn_list_free(struct ldb_context *ldb, struct dn_list *list)
50 for (i=0;i<list->count;i++) {
51 ldb_free(ldb, list->dn[i]);
53 ldb_free(ldb, list->dn);
57 return the dn key to be used for an index
60 static char *ldb_dn_key(struct ldb_context *ldb,
61 const char *attr, const struct ldb_val *value)
65 if (ldb_should_b64_encode(value)) {
66 char *vstr = ldb_base64_encode(ldb, value->data, value->length);
67 if (!vstr) return NULL;
68 ldb_asprintf(ldb, &ret, "%s:%s::%s", LTDB_INDEX, attr, vstr);
73 ldb_asprintf(ldb, &ret, "%s:%s:%s", LTDB_INDEX, attr, (char *)value->data);
78 see if a attribute value is in the list of indexed attributes
80 static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr,
81 int *v_idx, const char *key)
84 for (i=0;i<msg->num_elements;i++) {
85 if (ldb_attr_cmp(msg->elements[i].name, key) == 0) {
86 const struct ldb_message_element *el =
88 for (j=0;j<el->num_values;j++) {
89 if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) {
101 /* used in sorting dn lists */
102 static int list_cmp(const char **s1, const char **s2)
104 return strcmp(*s1, *s2);
108 return a list of dn's that might match a simple indexed search or
110 static int ltdb_index_dn_simple(struct ldb_context *ldb,
111 struct ldb_parse_tree *tree,
112 const struct ldb_message *index_list,
113 struct dn_list *list)
118 struct ldb_message msg;
124 if the value is a wildcard then we can't do a match via indexing
126 if (ltdb_has_wildcard(ldb, tree->u.simple.attr, &tree->u.simple.value)) {
130 /* if the attribute isn't in the list of indexed attributes then
131 this node needs a full search */
132 if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL, LTDB_IDXATTR) == -1) {
136 /* the attribute is indexed. Pull the list of DNs that match the
138 dn = ldb_dn_key(ldb, tree->u.simple.attr, &tree->u.simple.value);
141 ret = ltdb_search_dn1(ldb, dn, &msg);
143 if (ret == 0 || ret == -1) {
147 for (i=0;i<msg.num_elements;i++) {
148 struct ldb_message_element *el;
150 if (strcmp(msg.elements[i].name, LTDB_IDX) != 0) {
154 el = &msg.elements[i];
156 list->dn = ldb_malloc_array_p(ldb, char *, el->num_values);
161 for (j=0;j<el->num_values;j++) {
162 list->dn[list->count] =
163 ldb_strdup(ldb, (char *)el->values[j].data);
164 if (!list->dn[list->count]) {
165 dn_list_free(ldb, list);
166 ltdb_search_dn1_free(ldb, &msg);
173 ltdb_search_dn1_free(ldb, &msg);
175 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
181 static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *);
184 return a list of dn's that might match a simple indexed search on
185 the special objectclass attribute
187 static int ltdb_index_dn_objectclass(struct ldb_context *ldb,
188 struct ldb_parse_tree *tree,
189 const struct ldb_message *index_list,
190 struct dn_list *list)
192 struct ltdb_private *ltdb = ldb->private_data;
195 const char *target = tree->u.simple.value.data;
200 ret = ltdb_index_dn_simple(ldb, tree, index_list, list);
202 for (i=0;i<ltdb->cache.subclasses.num_elements;i++) {
203 struct ldb_message_element *el = <db->cache.subclasses.elements[i];
204 if (ldb_attr_cmp(el->name, target) == 0) {
206 for (j=0;j<el->num_values;j++) {
207 struct ldb_parse_tree tree2;
208 struct dn_list list2;
209 tree2.operation = LDB_OP_SIMPLE;
210 tree2.u.simple.attr = ldb_strdup(ldb, LTDB_OBJECTCLASS);
211 if (!tree2.u.simple.attr) {
214 tree2.u.simple.value = el->values[j];
215 if (ltdb_index_dn_objectclass(ldb, &tree2,
216 index_list, &list2) == 1) {
217 if (list->count == 0) {
221 list_union(ldb, list, &list2);
222 dn_list_free(ldb, &list2);
225 ldb_free(ldb, tree2.u.simple.attr);
234 return a list of dn's that might match a leaf indexed search
236 static int ltdb_index_dn_leaf(struct ldb_context *ldb,
237 struct ldb_parse_tree *tree,
238 const struct ldb_message *index_list,
239 struct dn_list *list)
241 if (ldb_attr_cmp(tree->u.simple.attr, LTDB_OBJECTCLASS) == 0) {
242 return ltdb_index_dn_objectclass(ldb, tree, index_list, list);
244 return ltdb_index_dn_simple(ldb, tree, index_list, list);
251 relies on the lists being sorted
253 static int list_intersect(struct ldb_context *ldb,
254 struct dn_list *list, const struct dn_list *list2)
256 struct dn_list list3;
259 if (list->count == 0 || list2->count == 0) {
261 dn_list_free(ldb, list);
265 list3.dn = ldb_malloc_array_p(ldb, char *, list->count);
267 dn_list_free(ldb, list);
272 for (i=0;i<list->count;i++) {
273 if (list_find(list->dn[i], list2->dn, list2->count,
274 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
275 list3.dn[list3.count] = list->dn[i];
278 ldb_free(ldb, list->dn[i]);
282 ldb_free(ldb, list->dn);
284 list->count = list3.count;
293 relies on the lists being sorted
295 static int list_union(struct ldb_context *ldb,
296 struct dn_list *list, const struct dn_list *list2)
300 unsigned int count = list->count;
302 if (list->count == 0 && list2->count == 0) {
304 dn_list_free(ldb, list);
308 d = ldb_realloc_p(ldb, list->dn, char *, list->count + list2->count);
310 dn_list_free(ldb, list);
315 for (i=0;i<list2->count;i++) {
316 if (list_find(list2->dn[i], list->dn, count,
317 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
318 list->dn[list->count] = ldb_strdup(ldb, list2->dn[i]);
319 if (!list->dn[list->count]) {
320 dn_list_free(ldb, list);
327 if (list->count != count) {
328 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
334 static int ltdb_index_dn(struct ldb_context *ldb,
335 struct ldb_parse_tree *tree,
336 const struct ldb_message *index_list,
337 struct dn_list *list);
343 static int ltdb_index_dn_or(struct ldb_context *ldb,
344 struct ldb_parse_tree *tree,
345 const struct ldb_message *index_list,
346 struct dn_list *list)
355 for (i=0;i<tree->u.list.num_elements;i++) {
356 struct dn_list list2;
358 v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
370 dn_list_free(ldb, list);
378 if (list_union(ldb, list, &list2) == -1) {
379 dn_list_free(ldb, &list2);
382 dn_list_free(ldb, &list2);
386 if (list->count == 0) {
387 dn_list_free(ldb, list);
398 static int ltdb_index_dn_not(struct ldb_context *ldb,
399 struct ldb_parse_tree *tree,
400 const struct ldb_message *index_list,
401 struct dn_list *list)
403 /* the only way to do an indexed not would be if we could
404 negate the not via another not or if we knew the total
405 number of database elements so we could know that the
406 existing expression covered the whole database.
408 instead, we just give up, and rely on a full index scan
409 (unless an outer & manages to reduce the list)
415 AND two index results
417 static int ltdb_index_dn_and(struct ldb_context *ldb,
418 struct ldb_parse_tree *tree,
419 const struct ldb_message *index_list,
420 struct dn_list *list)
429 for (i=0;i<tree->u.list.num_elements;i++) {
430 struct dn_list list2;
432 v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
436 dn_list_free(ldb, list);
448 if (list_intersect(ldb, list, &list2) == -1) {
449 dn_list_free(ldb, &list2);
452 dn_list_free(ldb, &list2);
455 if (list->count == 0) {
456 if (list->dn) ldb_free(ldb, list->dn);
465 return a list of dn's that might match a indexed search or
466 -1 if an error. return 0 for no matches, or 1 for matches
468 static int ltdb_index_dn(struct ldb_context *ldb,
469 struct ldb_parse_tree *tree,
470 const struct ldb_message *index_list,
471 struct dn_list *list)
475 switch (tree->operation) {
477 ret = ltdb_index_dn_leaf(ldb, tree, index_list, list);
481 ret = ltdb_index_dn_and(ldb, tree, index_list, list);
485 ret = ltdb_index_dn_or(ldb, tree, index_list, list);
489 ret = ltdb_index_dn_not(ldb, tree, index_list, list);
497 filter a candidate dn_list from an indexed search into a set of results
498 extracting just the given attributes
500 static int ldb_index_filter(struct ldb_context *ldb, struct ldb_parse_tree *tree,
502 enum ldb_scope scope,
503 const struct dn_list *dn_list,
504 const char * const attrs[], struct ldb_message ***res)
506 unsigned int count = 0, i;
508 for (i=0;i<dn_list->count;i++) {
509 struct ldb_message msg;
511 ret = ltdb_search_dn1(ldb, dn_list->dn[i], &msg);
513 /* the record has disappeared? yes, this can happen */
518 /* an internal error */
522 if (ldb_message_match(ldb, &msg, tree, base, scope) == 1) {
523 ret = ltdb_add_attr_results(ldb, &msg, attrs, &count, res);
525 ltdb_search_dn1_free(ldb, &msg);
535 search the database with a LDAP-like expression using indexes
536 returns -1 if an indexed search is not possible, in which
537 case the caller should call ltdb_search_full()
539 int ltdb_search_indexed(struct ldb_context *ldb,
541 enum ldb_scope scope,
542 struct ldb_parse_tree *tree,
543 const char * const attrs[], struct ldb_message ***res)
545 struct ltdb_private *ltdb = ldb->private_data;
546 struct dn_list dn_list;
549 if (ltdb->cache.indexlist.num_elements == 0) {
550 /* no index list? must do full search */
554 ret = ltdb_index_dn(ldb, tree, <db->cache.indexlist, &dn_list);
557 /* we've got a candidate list - now filter by the full tree
558 and extract the needed attributes */
559 ret = ldb_index_filter(ldb, tree, base, scope, &dn_list,
561 dn_list_free(ldb, &dn_list);
568 add a index element where this is the first indexed DN for this value
570 static int ltdb_index_add1_new(struct ldb_context *ldb,
571 struct ldb_message *msg,
572 struct ldb_message_element *el,
575 struct ldb_message_element *el2;
577 /* add another entry */
578 el2 = ldb_realloc_p(ldb, msg->elements,
579 struct ldb_message_element, msg->num_elements+1);
585 msg->elements[msg->num_elements].name = ldb_strdup(ldb, LTDB_IDX);
586 if (!msg->elements[msg->num_elements].name) {
589 msg->elements[msg->num_elements].num_values = 0;
590 msg->elements[msg->num_elements].values = ldb_malloc_p(ldb, struct ldb_val);
591 if (!msg->elements[msg->num_elements].values) {
594 msg->elements[msg->num_elements].values[0].length = strlen(dn);
595 msg->elements[msg->num_elements].values[0].data = dn;
596 msg->elements[msg->num_elements].num_values = 1;
604 add a index element where this is not the first indexed DN for this
607 static int ltdb_index_add1_add(struct ldb_context *ldb,
608 struct ldb_message *msg,
609 struct ldb_message_element *el,
616 /* for multi-valued attributes we can end up with repeats */
617 for (i=0;i<msg->elements[idx].num_values;i++) {
618 if (strcmp(dn, msg->elements[idx].values[i].data) == 0) {
623 v2 = ldb_realloc_p(ldb, msg->elements[idx].values,
625 msg->elements[idx].num_values+1);
629 msg->elements[idx].values = v2;
631 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
632 msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
633 msg->elements[idx].num_values++;
639 add an index entry for one message element
641 static int ltdb_index_add1(struct ldb_context *ldb, char *dn,
642 struct ldb_message_element *el, int v_idx)
644 struct ldb_message msg;
646 int ret, added=0, added_dn=0;
649 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
654 ret = ltdb_search_dn1(ldb, dn_key, &msg);
656 ldb_free(ldb, dn_key);
662 msg.dn = ldb_strdup(ldb, dn_key);
664 ldb_free(ldb, dn_key);
668 msg.num_elements = 0;
670 msg.private_data = NULL;
673 ldb_free(ldb, dn_key);
675 for (i=0;i<msg.num_elements;i++) {
676 if (strcmp(LTDB_IDX, msg.elements[i].name) == 0) {
681 if (i == msg.num_elements) {
683 ret = ltdb_index_add1_new(ldb, &msg, el, dn);
685 ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
689 ret = ltdb_store(ldb, &msg, TDB_REPLACE);
693 ldb_free(ldb, msg.elements[i].name);
696 ldb_free(ldb, msg.dn);
699 ltdb_search_dn1_free(ldb, &msg);
705 add the index entries for a new record
708 int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
710 struct ltdb_private *ltdb = ldb->private_data;
714 if (ltdb->cache.indexlist.num_elements == 0) {
715 /* no indexed fields */
719 for (i=0;i<msg->num_elements;i++) {
720 ret = ldb_msg_find_idx(<db->cache.indexlist, msg->elements[i].name,
725 for (j=0;j<msg->elements[i].num_values;j++) {
726 ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i], j);
738 delete an index entry for one message element
740 static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
741 struct ldb_message_element *el, int v_idx)
743 struct ldb_message msg;
748 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
753 ret = ltdb_search_dn1(ldb, dn_key, &msg);
755 ldb_free(ldb, dn_key);
760 /* it wasn't indexed. Did we have an earlier error? If we did then
762 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn_key %s was not indexed\n", dn_key);
763 ldb_free(ldb, dn_key);
767 i = ldb_msg_find_idx(&msg, dn, &j, LTDB_IDX);
769 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn %s not found in %s\n", dn, dn_key);
770 /* it ain't there. hmmm */
771 ltdb_search_dn1_free(ldb, &msg);
772 ldb_free(ldb, dn_key);
776 if (j != msg.elements[i].num_values - 1) {
777 memmove(&msg.elements[i].values[j],
778 &msg.elements[i].values[j+1],
779 (msg.elements[i].num_values-(j+1)) *
780 sizeof(msg.elements[i].values[0]));
782 msg.elements[i].num_values--;
784 if (msg.elements[i].num_values == 0) {
785 ret = ltdb_delete_noindex(ldb, dn_key);
787 ret = ltdb_store(ldb, &msg, TDB_REPLACE);
790 ltdb_search_dn1_free(ldb, &msg);
791 ldb_free(ldb, dn_key);
797 delete the index entries for a record
800 int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
802 struct ltdb_private *ltdb = ldb->private_data;
806 /* find the list of indexed fields */
807 if (ltdb->cache.indexlist.num_elements == 0) {
808 /* no indexed fields */
812 for (i=0;i<msg->num_elements;i++) {
813 ret = ldb_msg_find_idx(<db->cache.indexlist, msg->elements[i].name,
818 for (j=0;j<msg->elements[i].num_values;j++) {
819 ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i], j);
831 traversal function that deletes all @INDEX records
833 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
835 const char *dn = "DN=" LTDB_INDEX ":";
836 if (strncmp(key.dptr, dn, strlen(dn)) == 0) {
837 return tdb_delete(tdb, key);
843 traversal function that adds @INDEX records during a re index
845 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
847 struct ldb_context *ldb = state;
848 struct ldb_message msg;
851 if (strncmp(key.dptr, "DN=@", 4) == 0 ||
852 strncmp(key.dptr, "DN=", 3) != 0) {
856 ret = ltdb_unpack_data(ldb, &data, &msg);
865 ret = ltdb_index_add(ldb, &msg);
867 ltdb_unpack_data_free(ldb, &msg);
873 force a complete reindex of the database
875 int ltdb_reindex(struct ldb_context *ldb)
877 struct ltdb_private *ltdb = ldb->private_data;
880 ltdb_cache_free(ldb);
882 if (ltdb_cache_load(ldb) != 0) {
886 /* first traverse the database deleting any @INDEX records */
887 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
893 /* now traverse adding any indexes for normal LDB records */
894 ret = tdb_traverse(ltdb->tdb, re_index, ldb);