]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/index.c
Fix subtype indexing. Really really made it the default.
[openldap] / servers / slapd / back-bdb / index.c
1 /* index.c - routines for dealing with attribute indexes */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/string.h>
13 #include <ac/socket.h>
14
15 #include "slap.h"
16 #include "back-bdb.h"
17 #include "lutil_hash.h"
18
19 static char presence_keyval[LUTIL_HASH_BYTES] = {0,0,0,1};
20 static struct berval presence_key = {LUTIL_HASH_BYTES, presence_keyval};
21
22 static slap_mask_t index_mask(
23         Backend *be,
24         AttributeDescription *desc,
25         char **dbname,
26         struct berval *atname )
27 {
28         AttributeType *at;
29         slap_mask_t mask = 0;
30
31         bdb_attr_mask( be->be_private, desc, &mask );
32
33         if( mask ) {
34                 *atname = desc->ad_cname;
35                 *dbname = desc->ad_cname.bv_val;
36                 return mask;
37         }
38
39         /* If there is a language tag, did we ever index the base
40          * type? If so, check for mask, otherwise it's not there.
41          */
42         if( slap_ad_is_lang( desc ) && desc != desc->ad_type->sat_ad ) {
43                 /* has language tag */
44                 bdb_attr_mask( be->be_private, desc->ad_type->sat_ad, &mask );
45
46                 if ( mask && ( mask ^ SLAP_INDEX_NOLANG ) ) {
47                         *atname = desc->ad_type->sat_cname;
48                         *dbname = desc->ad_type->sat_cname.bv_val;
49                         return mask;
50                 }
51         }
52
53         /* see if supertype defined mask for its subtypes */
54         for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
55                 /* If no AD, we've never indexed this type */
56                 if ( !at->sat_ad ) continue;
57
58                 bdb_attr_mask( be->be_private, at->sat_ad, &mask );
59
60                 if ( mask && ( mask ^ SLAP_INDEX_NOSUBTYPES ) ) {
61                         *atname = desc->ad_type->sat_cname;
62                         *dbname = at->sat_cname.bv_val;
63                         return mask;
64                 }
65         }
66
67         return 0;
68 }
69
70 int bdb_index_is_indexed(
71         Backend *be,
72         AttributeDescription *desc )
73 {
74         int rc;
75         slap_mask_t mask;
76         char *dbname;
77         struct berval prefix;
78
79         mask = index_mask( be, desc, &dbname, &prefix );
80
81         if( mask == 0 ) {
82                 return LDAP_INAPPROPRIATE_MATCHING;
83         }
84
85         return LDAP_SUCCESS;
86 }
87
88 int bdb_index_param(
89         Backend *be,
90         AttributeDescription *desc,
91         int ftype,
92         DB **dbp,
93         slap_mask_t *maskp,
94         struct berval *prefixp )
95 {
96         int rc;
97         slap_mask_t mask;
98         DB *db;
99         char *dbname;
100
101         mask = index_mask( be, desc, &dbname, prefixp );
102
103         if( mask == 0 ) {
104                 return LDAP_INAPPROPRIATE_MATCHING;
105         }
106
107         rc = bdb_db_cache( be, dbname, &db );
108
109         if( rc != LDAP_SUCCESS ) {
110                 return rc;
111         }
112
113         switch( ftype ) {
114         case LDAP_FILTER_PRESENT:
115                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
116                         goto done;
117                 }
118                 break;
119
120         case LDAP_FILTER_APPROX:
121                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
122                         goto done;
123                 }
124                 /* fall thru */
125
126         case LDAP_FILTER_EQUALITY:
127                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
128                         goto done;
129                 }
130                 break;
131
132         case LDAP_FILTER_SUBSTRINGS:
133                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
134                         goto done;
135                 }
136                 break;
137
138         default:
139                 return LDAP_OTHER;
140         }
141
142         return LDAP_INAPPROPRIATE_MATCHING;
143
144 done:
145         *dbp = db;
146         *maskp = mask;
147         return LDAP_SUCCESS;
148 }
149
150 static int indexer(
151         Backend *be,
152         DB_TXN *txn,
153         char *dbname,
154         struct berval *atname,
155         BerVarray vals,
156         ID id,
157         int op,
158         slap_mask_t mask )
159 {
160         int rc, i;
161         const char *text;
162         DB *db;
163         AttributeDescription *ad = NULL;
164         struct berval *keys;
165
166         assert( mask );
167
168         rc = bdb_db_cache( be, dbname, &db );
169         
170         if ( rc != LDAP_SUCCESS ) {
171 #ifdef NEW_LOGGING
172                 LDAP_LOG(( "index", LDAP_LEVEL_ERR,
173                         "bdb_index_read: Could not open DB %s\n", dbname));
174 #else
175                 Debug( LDAP_DEBUG_ANY,
176                         "<= bdb_index_read NULL (could not open %s)\n",
177                         dbname, 0, 0 );
178 #endif
179                 return LDAP_OTHER;
180         }
181
182         rc = slap_bv2ad( atname, &ad, &text );
183         if( rc != LDAP_SUCCESS ) return rc;
184
185         if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
186                 rc = bdb_key_change( be, db, txn, &presence_key, id, op );
187                 if( rc ) {
188                         goto done;
189                 }
190         }
191
192         if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
193                 rc = ad->ad_type->sat_equality->smr_indexer(
194                         LDAP_FILTER_EQUALITY,
195                         mask,
196                         ad->ad_type->sat_syntax,
197                         ad->ad_type->sat_equality,
198                         atname, vals, &keys );
199
200                 if( rc == LDAP_SUCCESS && keys != NULL ) {
201                         for( i=0; keys[i].bv_val != NULL; i++ ) {
202                                 rc = bdb_key_change( be, db, txn, &keys[i], id, op );
203                                 if( rc ) {
204                                         ber_bvarray_free( keys );
205                                         goto done;
206                                 }
207                         }
208                         ber_bvarray_free( keys );
209                 }
210                 rc = LDAP_SUCCESS;
211         }
212
213         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
214                 rc = ad->ad_type->sat_approx->smr_indexer(
215                         LDAP_FILTER_APPROX,
216                         mask,
217                         ad->ad_type->sat_syntax,
218                         ad->ad_type->sat_approx,
219                         atname, vals, &keys );
220
221                 if( rc == LDAP_SUCCESS && keys != NULL ) {
222                         for( i=0; keys[i].bv_val != NULL; i++ ) {
223                                 rc = bdb_key_change( be, db, txn, &keys[i], id, op );
224                                 if( rc ) {
225                                         ber_bvarray_free( keys );
226                                         goto done;
227                                 }
228                         }
229                         ber_bvarray_free( keys );
230                 }
231
232                 rc = LDAP_SUCCESS;
233         }
234
235         if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
236                 rc = ad->ad_type->sat_substr->smr_indexer(
237                         LDAP_FILTER_SUBSTRINGS,
238                         mask,
239                         ad->ad_type->sat_syntax,
240                         ad->ad_type->sat_substr,
241                         atname, vals, &keys );
242
243                 if( rc == LDAP_SUCCESS && keys != NULL ) {
244                         for( i=0; keys[i].bv_val != NULL; i++ ) {
245                                 bdb_key_change( be, db, txn, &keys[i], id, op );
246                                 if( rc ) {
247                                         ber_bvarray_free( keys );
248                                         goto done;
249                                 }
250                         }
251                         ber_bvarray_free( keys );
252                 }
253
254                 rc = LDAP_SUCCESS;
255         }
256
257 done:
258         return rc;
259 }
260
261 static int index_at_values(
262         Backend *be,
263         DB_TXN *txn,
264         AttributeType *type,
265         struct berval *lang,
266         BerVarray vals,
267         ID id,
268         int op,
269         char ** dbnamep,
270         slap_mask_t *maskp )
271 {
272         int rc;
273         slap_mask_t mask = 0;
274         slap_mask_t tmpmask = 0;
275         int lindex = 0;
276
277         if( type->sat_sup ) {
278                 /* recurse */
279                 rc = index_at_values( be, txn,
280                         type->sat_sup, lang,
281                         vals, id, op,
282                         dbnamep, &tmpmask );
283
284                 if( rc ) return rc;
285         }
286
287         /* If this type has no AD, we've never used it before */
288         if( type->sat_ad ) {
289                 bdb_attr_mask( be->be_private, type->sat_ad, &mask );
290         }
291
292         if( mask ) {
293                 *dbnamep = type->sat_cname.bv_val;
294         } else if ( tmpmask ^ SLAP_INDEX_NOSUBTYPES ) {
295                 mask = tmpmask;
296         }
297
298         if( mask ) {
299                 rc = indexer( be, txn, *dbnamep,
300                         &type->sat_cname,
301                         vals, id, op,
302                         mask );
303
304                 if( rc ) return rc;
305                 *maskp = mask;
306         }
307
308         if( lang->bv_len ) {
309                 char *dbname = NULL;
310                 struct berval lname;
311                 AttributeDescription *desc;
312
313                 tmpmask = 0;
314                 lname.bv_val = NULL;
315
316                 desc = ad_find_lang( type, lang );
317                 if( desc ) {
318                         bdb_attr_mask( be->be_private, desc, &tmpmask );
319                 }
320
321                 if( tmpmask ) {
322                         dbname = desc->ad_cname.bv_val;
323                         lname = desc->ad_cname;
324                         mask = tmpmask;
325                 }
326
327                 if( dbname != NULL ) {
328                         rc = indexer( be, txn, dbname, &lname,
329                                 vals, id, op,
330                                 mask );
331
332                         if( !tmpmask ) {
333                                 ch_free( lname.bv_val );
334                         }
335                         if( rc ) {
336                                 return rc;
337                         }
338                 }
339         }
340
341         return LDAP_SUCCESS;
342 }
343
344 int bdb_index_values(
345         Backend *be,
346         DB_TXN *txn,
347         AttributeDescription *desc,
348         BerVarray vals,
349         ID id,
350         int op )
351 {
352         int rc;
353         char *dbname = NULL;
354         slap_mask_t mask;
355
356         rc = index_at_values( be, txn,
357                 desc->ad_type, &desc->ad_lang,
358                 vals, id, op,
359                 &dbname, &mask );
360
361         return rc;
362 }
363
364 int
365 bdb_index_entry(
366         Backend *be,
367         DB_TXN *txn,
368         int op,
369         Entry   *e,
370         Attribute *ap )
371 {
372         int rc;
373
374 #ifdef NEW_LOGGING
375         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
376                 "index_entry: %s (%s) %ld\n",
377                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
378                 e->e_dn, (long) e->e_id ));
379 #else
380         Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
381                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
382                 (long) e->e_id, e->e_dn );
383 #endif
384
385         /* add each attribute to the indexes */
386         for ( ; ap != NULL; ap = ap->a_next ) {
387                 rc = bdb_index_values( be, txn,
388                         ap->a_desc, ap->a_vals, e->e_id, op );
389
390                 if( rc != LDAP_SUCCESS ) {
391 #ifdef NEW_LOGGING
392                         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
393                                 "index_entry: success\n" ));
394 #else
395                         Debug( LDAP_DEBUG_TRACE,
396                                 "<= index_entry_%s( %ld, \"%s\" ) success\n",
397                                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
398                                 (long) e->e_id, e->e_dn );
399 #endif
400                         return rc;
401                 }
402         }
403
404 #ifdef NEW_LOGGING
405         LDAP_LOG(( "index", LDAP_LEVEL_ENTRY,
406                 "index_entry: success\n" ));
407 #else
408         Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
409                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
410                 (long) e->e_id, e->e_dn );
411 #endif
412
413         return LDAP_SUCCESS;
414 }