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)
117 struct ldb_message msg;
123 if the value is a wildcard then we can't do a match via indexing
125 if (ltdb_has_wildcard(ldb, tree->u.simple.attr, &tree->u.simple.value)) {
129 /* if the attribute isn't in the list of indexed attributes then
130 this node needs a full search */
131 if (ldb_msg_find_idx(index_list, tree->u.simple.attr, NULL, LTDB_IDXATTR) == -1) {
135 /* the attribute is indexed. Pull the list of DNs that match the
137 dn = ldb_dn_key(ldb, tree->u.simple.attr, &tree->u.simple.value);
140 ret = ltdb_search_dn1(ldb, dn, &msg);
142 if (ret == 0 || ret == -1) {
146 for (i=0;i<msg.num_elements;i++) {
147 struct ldb_message_element *el;
149 if (strcmp(msg.elements[i].name, LTDB_IDX) != 0) {
153 el = &msg.elements[i];
155 list->dn = ldb_malloc_array_p(ldb, char *, el->num_values);
160 for (j=0;j<el->num_values;j++) {
161 list->dn[list->count] =
162 ldb_strdup(ldb, (char *)el->values[j].data);
163 if (!list->dn[list->count]) {
164 dn_list_free(ldb, list);
165 ltdb_search_dn1_free(ldb, &msg);
172 ltdb_search_dn1_free(ldb, &msg);
174 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp);
180 return a list of dn's that might match a simple indexed search on
181 the special objectclass attribute
183 static int ltdb_index_dn_objectclass(struct ldb_context *ldb,
184 struct ldb_parse_tree *tree,
185 const struct ldb_message *index_list,
186 struct dn_list *list)
188 struct ltdb_private *ltdb = ldb->private_data;
191 const char *target = tree->u.simple.value.data;
192 static int list_union(struct ldb_context *,
193 struct dn_list *, const struct dn_list *);
198 ret = ltdb_index_dn_simple(ldb, tree, index_list, list);
200 for (i=0;i<ltdb->cache.subclasses.num_elements;i++) {
201 struct ldb_message_element *el = <db->cache.subclasses.elements[i];
202 if (ldb_attr_cmp(el->name, target) == 0) {
204 for (j=0;j<el->num_values;j++) {
205 struct ldb_parse_tree tree2;
206 struct dn_list list2;
207 tree2.operation = LDB_OP_SIMPLE;
208 tree2.u.simple.attr = ldb_strdup(ldb, LTDB_OBJECTCLASS);
209 if (!tree2.u.simple.attr) {
212 tree2.u.simple.value = el->values[j];
213 if (ltdb_index_dn_objectclass(ldb, &tree2,
214 index_list, &list2) == 1) {
215 if (list->count == 0) {
219 list_union(ldb, list, &list2);
220 dn_list_free(ldb, &list2);
223 ldb_free(ldb, tree2.u.simple.attr);
232 return a list of dn's that might match a leaf indexed search
234 static int ltdb_index_dn_leaf(struct ldb_context *ldb,
235 struct ldb_parse_tree *tree,
236 const struct ldb_message *index_list,
237 struct dn_list *list)
239 if (ldb_attr_cmp(tree->u.simple.attr, LTDB_OBJECTCLASS) == 0) {
240 return ltdb_index_dn_objectclass(ldb, tree, index_list, list);
242 return ltdb_index_dn_simple(ldb, tree, index_list, list);
249 relies on the lists being sorted
251 static int list_intersect(struct ldb_context *ldb,
252 struct dn_list *list, const struct dn_list *list2)
254 struct dn_list list3;
257 if (list->count == 0 || list2->count == 0) {
259 dn_list_free(ldb, list);
263 list3.dn = ldb_malloc_array_p(ldb, char *, list->count);
265 dn_list_free(ldb, list);
270 for (i=0;i<list->count;i++) {
271 if (list_find(list->dn[i], list2->dn, list2->count,
272 sizeof(char *), (comparison_fn_t)strcmp) != -1) {
273 list3.dn[list3.count] = list->dn[i];
276 ldb_free(ldb, list->dn[i]);
280 ldb_free(ldb, list->dn);
282 list->count = list3.count;
291 relies on the lists being sorted
293 static int list_union(struct ldb_context *ldb,
294 struct dn_list *list, const struct dn_list *list2)
298 unsigned int count = list->count;
300 if (list->count == 0 && list2->count == 0) {
302 dn_list_free(ldb, list);
306 d = ldb_realloc_p(ldb, list->dn, char *, list->count + list2->count);
308 dn_list_free(ldb, list);
313 for (i=0;i<list2->count;i++) {
314 if (list_find(list2->dn[i], list->dn, count,
315 sizeof(char *), (comparison_fn_t)strcmp) == -1) {
316 list->dn[list->count] = ldb_strdup(ldb, list2->dn[i]);
317 if (!list->dn[list->count]) {
318 dn_list_free(ldb, list);
325 if (list->count != count) {
326 qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp);
332 static int ltdb_index_dn(struct ldb_context *ldb,
333 struct ldb_parse_tree *tree,
334 const struct ldb_message *index_list,
335 struct dn_list *list);
341 static int ltdb_index_dn_or(struct ldb_context *ldb,
342 struct ldb_parse_tree *tree,
343 const struct ldb_message *index_list,
344 struct dn_list *list)
352 for (i=0;i<tree->u.list.num_elements;i++) {
353 struct dn_list list2;
355 v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
367 dn_list_free(ldb, list);
375 if (list_union(ldb, list, &list2) == -1) {
376 dn_list_free(ldb, &list2);
379 dn_list_free(ldb, &list2);
383 if (list->count == 0) {
384 dn_list_free(ldb, list);
395 static int ltdb_index_dn_not(struct ldb_context *ldb,
396 struct ldb_parse_tree *tree,
397 const struct ldb_message *index_list,
398 struct dn_list *list)
400 /* the only way to do an indexed not would be if we could
401 negate the not via another not or if we knew the total
402 number of database elements so we could know that the
403 existing expression covered the whole database.
405 instead, we just give up, and rely on a full index scan
406 (unless an outer & manages to reduce the list)
412 AND two index results
414 static int ltdb_index_dn_and(struct ldb_context *ldb,
415 struct ldb_parse_tree *tree,
416 const struct ldb_message *index_list,
417 struct dn_list *list)
425 for (i=0;i<tree->u.list.num_elements;i++) {
426 struct dn_list list2;
428 v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
432 dn_list_free(ldb, list);
444 if (list_intersect(ldb, list, &list2) == -1) {
445 dn_list_free(ldb, &list2);
448 dn_list_free(ldb, &list2);
451 if (list->count == 0) {
452 if (list->dn) ldb_free(ldb, list->dn);
461 return a list of dn's that might match a indexed search or
462 -1 if an error. return 0 for no matches, or 1 for matches
464 static int ltdb_index_dn(struct ldb_context *ldb,
465 struct ldb_parse_tree *tree,
466 const struct ldb_message *index_list,
467 struct dn_list *list)
471 switch (tree->operation) {
473 ret = ltdb_index_dn_leaf(ldb, tree, index_list, list);
477 ret = ltdb_index_dn_and(ldb, tree, index_list, list);
481 ret = ltdb_index_dn_or(ldb, tree, index_list, list);
485 ret = ltdb_index_dn_not(ldb, tree, index_list, list);
493 filter a candidate dn_list from an indexed search into a set of results
494 extracting just the given attributes
496 static int ldb_index_filter(struct ldb_context *ldb, struct ldb_parse_tree *tree,
498 enum ldb_scope scope,
499 const struct dn_list *dn_list,
500 const char * const attrs[], struct ldb_message ***res)
503 unsigned int count = 0;
505 for (i=0;i<dn_list->count;i++) {
506 struct ldb_message msg;
508 ret = ltdb_search_dn1(ldb, dn_list->dn[i], &msg);
510 /* the record has disappeared? yes, this can happen */
515 /* an internal error */
519 if (ldb_message_match(ldb, &msg, tree, base, scope) == 1) {
520 ret = ltdb_add_attr_results(ldb, &msg, attrs, &count, res);
522 ltdb_search_dn1_free(ldb, &msg);
532 search the database with a LDAP-like expression using indexes
533 returns -1 if an indexed search is not possible, in which
534 case the caller should call ltdb_search_full()
536 int ltdb_search_indexed(struct ldb_context *ldb,
538 enum ldb_scope scope,
539 struct ldb_parse_tree *tree,
540 const char * const attrs[], struct ldb_message ***res)
542 struct ltdb_private *ltdb = ldb->private_data;
543 struct dn_list dn_list;
546 if (ltdb->cache.indexlist.num_elements == 0) {
547 /* no index list? must do full search */
551 ret = ltdb_index_dn(ldb, tree, <db->cache.indexlist, &dn_list);
554 /* we've got a candidate list - now filter by the full tree
555 and extract the needed attributes */
556 ret = ldb_index_filter(ldb, tree, base, scope, &dn_list,
558 dn_list_free(ldb, &dn_list);
565 add a index element where this is the first indexed DN for this value
567 static int ltdb_index_add1_new(struct ldb_context *ldb,
568 struct ldb_message *msg,
569 struct ldb_message_element *el,
572 struct ldb_message_element *el2;
574 /* add another entry */
575 el2 = ldb_realloc_p(ldb, msg->elements,
576 struct ldb_message_element, msg->num_elements+1);
582 msg->elements[msg->num_elements].name = ldb_strdup(ldb, LTDB_IDX);
583 if (!msg->elements[msg->num_elements].name) {
586 msg->elements[msg->num_elements].num_values = 0;
587 msg->elements[msg->num_elements].values = ldb_malloc_p(ldb, struct ldb_val);
588 if (!msg->elements[msg->num_elements].values) {
591 msg->elements[msg->num_elements].values[0].length = strlen(dn);
592 msg->elements[msg->num_elements].values[0].data = dn;
593 msg->elements[msg->num_elements].num_values = 1;
601 add a index element where this is not the first indexed DN for this
604 static int ltdb_index_add1_add(struct ldb_context *ldb,
605 struct ldb_message *msg,
606 struct ldb_message_element *el,
613 /* for multi-valued attributes we can end up with repeats */
614 for (i=0;i<msg->elements[idx].num_values;i++) {
615 if (strcmp(dn, msg->elements[idx].values[i].data) == 0) {
620 v2 = ldb_realloc_p(ldb, msg->elements[idx].values,
622 msg->elements[idx].num_values+1);
626 msg->elements[idx].values = v2;
628 msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn);
629 msg->elements[idx].values[msg->elements[idx].num_values].data = dn;
630 msg->elements[idx].num_values++;
636 add an index entry for one message element
638 static int ltdb_index_add1(struct ldb_context *ldb, char *dn,
639 struct ldb_message_element *el, int v_idx)
641 struct ldb_message msg;
643 int ret, i, added=0, added_dn=0;
645 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
650 ret = ltdb_search_dn1(ldb, dn_key, &msg);
652 ldb_free(ldb, dn_key);
658 msg.dn = ldb_strdup(ldb, dn_key);
660 ldb_free(ldb, dn_key);
664 msg.num_elements = 0;
666 msg.private_data = NULL;
669 ldb_free(ldb, dn_key);
671 for (i=0;i<msg.num_elements;i++) {
672 if (strcmp(LTDB_IDX, msg.elements[i].name) == 0) {
677 if (i == msg.num_elements) {
679 ret = ltdb_index_add1_new(ldb, &msg, el, dn);
681 ret = ltdb_index_add1_add(ldb, &msg, el, i, dn);
685 ret = ltdb_store(ldb, &msg, TDB_REPLACE);
689 ldb_free(ldb, msg.elements[i].name);
692 ldb_free(ldb, msg.dn);
695 ltdb_search_dn1_free(ldb, &msg);
701 add the index entries for a new record
704 int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
706 struct ltdb_private *ltdb = ldb->private_data;
709 if (ltdb->cache.indexlist.num_elements == 0) {
710 /* no indexed fields */
714 for (i=0;i<msg->num_elements;i++) {
715 ret = ldb_msg_find_idx(<db->cache.indexlist, msg->elements[i].name,
720 for (j=0;j<msg->elements[i].num_values;j++) {
721 ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i], j);
733 delete an index entry for one message element
735 static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
736 struct ldb_message_element *el, int v_idx)
738 struct ldb_message msg;
742 dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]);
747 ret = ltdb_search_dn1(ldb, dn_key, &msg);
749 ldb_free(ldb, dn_key);
754 /* it wasn't indexed. Did we have an earlier error? If we did then
756 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn_key %s was not indexed\n", dn_key);
757 ldb_free(ldb, dn_key);
761 i = ldb_msg_find_idx(&msg, dn, &j, LTDB_IDX);
763 ldb_debug(ldb, LDB_DEBUG_ERROR, "ERROR: dn %s not found in %s\n", dn, dn_key);
764 /* it ain't there. hmmm */
765 ltdb_search_dn1_free(ldb, &msg);
766 ldb_free(ldb, dn_key);
770 if (j != msg.elements[i].num_values - 1) {
771 memmove(&msg.elements[i].values[j],
772 &msg.elements[i].values[j+1],
773 (msg.elements[i].num_values-(j+1)) *
774 sizeof(msg.elements[i].values[0]));
776 msg.elements[i].num_values--;
778 if (msg.elements[i].num_values == 0) {
779 ret = ltdb_delete_noindex(ldb, dn_key);
781 ret = ltdb_store(ldb, &msg, TDB_REPLACE);
784 ltdb_search_dn1_free(ldb, &msg);
785 ldb_free(ldb, dn_key);
791 delete the index entries for a record
794 int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
796 struct ltdb_private *ltdb = ldb->private_data;
799 /* find the list of indexed fields */
800 if (ltdb->cache.indexlist.num_elements == 0) {
801 /* no indexed fields */
805 for (i=0;i<msg->num_elements;i++) {
806 ret = ldb_msg_find_idx(<db->cache.indexlist, msg->elements[i].name,
811 for (j=0;j<msg->elements[i].num_values;j++) {
812 ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i], j);
824 traversal function that deletes all @INDEX records
826 static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
828 const char *dn = "DN=" LTDB_INDEX ":";
829 if (strncmp(key.dptr, dn, strlen(dn)) == 0) {
830 return tdb_delete(tdb, key);
836 traversal function that adds @INDEX records during a re index
838 static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
840 struct ldb_context *ldb = state;
841 struct ldb_message msg;
844 if (strncmp(key.dptr, "DN=@", 4) == 0 ||
845 strncmp(key.dptr, "DN=", 3) != 0) {
849 ret = ltdb_unpack_data(ldb, &data, &msg);
858 ret = ltdb_index_add(ldb, &msg);
860 ltdb_unpack_data_free(ldb, &msg);
866 force a complete reindex of the database
868 int ltdb_reindex(struct ldb_context *ldb)
870 struct ltdb_private *ltdb = ldb->private_data;
873 ltdb_cache_free(ldb);
875 if (ltdb_cache_load(ldb) != 0) {
879 /* first traverse the database deleting any @INDEX records */
880 ret = tdb_traverse(ltdb->tdb, delete_index, NULL);
886 /* now traverse adding any indexes for normal LDB records */
887 ret = tdb_traverse(ltdb->tdb, re_index, ldb);