]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/index.c
ITS#189 fix: indexed normalized(e_dn) without recomputing length.
[openldap] / servers / slapd / back-ldbm / index.c
1 /* index.c - routines for dealing with attribute indexes */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/socket.h>
9
10 #include "slap.h"
11 #include "back-ldbm.h"
12
13 static int      add_value(Backend *be, struct dbcache *db, char *type, int indextype, char *val, ID id);
14 static int      index2prefix(int indextype);
15
16 int
17 index_add_entry(
18     Backend     *be,
19     Entry       *e
20 )
21 {
22         Attribute       *ap;
23         char            *dnval;
24         struct berval   bv;
25         struct berval   *bvals[2];
26
27         Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
28             e->e_dn, 0 );
29
30         /*
31          * dn index entry - make it look like an attribute so it works
32          * with index_add_values() call
33          */
34
35         bv.bv_val = ch_strdup( e->e_ndn );
36         bv.bv_len = strlen( bv.bv_val );
37         bvals[0] = &bv;
38         bvals[1] = NULL;
39
40         /* add the dn to the indexes */
41         {
42                 char *dn = ch_strdup("dn");
43                 index_add_values( be, dn, bvals, e->e_id );
44                 free( dn );
45         }
46
47         free( bv.bv_val );
48
49         /* add each attribute to the indexes */
50         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
51                 index_add_values( be, ap->a_type, ap->a_vals, e->e_id );
52         }
53
54         Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
55             e->e_ndn, 0 );
56         return( 0 );
57 }
58
59 int
60 index_add_mods(
61     Backend     *be,
62     LDAPMod     *mods,
63     ID          id
64 )
65 {
66         int     rc;
67
68         for ( ; mods != NULL; mods = mods->mod_next ) {
69                 switch ( mods->mod_op & ~LDAP_MOD_BVALUES ) {
70                 case LDAP_MOD_ADD:
71                 case LDAP_MOD_REPLACE:
72                         rc = index_add_values( be, mods->mod_type,
73                             mods->mod_bvalues, id );
74                         break;
75                 case LDAP_MOD_SOFTADD:  /* SOFTADD means index was there already */
76                 case LDAP_MOD_DELETE:
77                         rc = 0;
78                         break;
79                 }
80
81                 if ( rc != 0 ) {
82                         return( rc );
83                 }
84         }
85
86         return( 0 );
87 }
88
89 ID_BLOCK *
90 index_read(
91     Backend     *be,
92     char        *type,
93     int         indextype,
94     char        *val
95 )
96 {
97         struct dbcache  *db;
98         Datum           key;
99         ID_BLOCK                *idl;
100         int             indexmask, syntax;
101         char            prefix;
102         char            *realval, *tmpval;
103         char            buf[BUFSIZ];
104
105         ldbm_datum_init( key );
106
107         prefix = index2prefix( indextype );
108         Debug( LDAP_DEBUG_TRACE, "=> index_read( \"%s\" \"%c\" \"%s\" )\n",
109             type, prefix, val );
110
111         attr_masks( be->be_private, type, &indexmask, &syntax );
112         if ( ! (indextype & indexmask) ) {
113                 idl =  idl_allids( be );
114                 Debug( LDAP_DEBUG_TRACE,
115                     "<= index_read %lu candidates (allids - not indexed)\n",
116                     idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
117                 return( idl );
118         }
119
120         attr_normalize( type );
121         if ( (db = ldbm_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
122             == NULL ) {
123                 Debug( LDAP_DEBUG_ANY,
124                     "<= index_read NULL (could not open %s%s)\n", type,
125                     LDBM_SUFFIX, 0 );
126                 return( NULL );
127         }
128
129         realval = val;
130         tmpval = NULL;
131         if ( prefix != UNKNOWN_PREFIX ) {
132               unsigned int      len = strlen( val );
133
134               if ( (len + 2) < sizeof(buf) ) {
135                         realval = buf;
136                 } else {
137                         /* value + prefix + null */
138                         tmpval = (char *) ch_malloc( len + 2 );
139                         realval = tmpval;
140                 }
141               realval[0] = prefix;
142               strcpy( &realval[1], val );
143         }
144
145         key.dptr = realval;
146         key.dsize = strlen( realval ) + 1;
147
148         idl = idl_fetch( be, db, key );
149       if ( tmpval != NULL ) {
150               free( tmpval );
151       }
152
153         ldbm_cache_close( be, db );
154
155         Debug( LDAP_DEBUG_TRACE, "<= index_read %lu candidates\n",
156             idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
157         return( idl );
158 }
159
160 static int
161 add_value(
162     Backend             *be,
163     struct dbcache      *db,
164     char                *type,
165     int                 indextype,
166     char                *val,
167     ID                  id
168 )
169 {
170         int     rc;
171         Datum   key;
172         ID_BLOCK        *idl = NULL;
173         char    *tmpval = NULL;
174         char    *realval = val;
175         char    buf[BUFSIZ];
176
177         char    prefix = index2prefix( indextype );
178
179         ldbm_datum_init( key );
180
181         Debug( LDAP_DEBUG_TRACE, "=> add_value( \"%c%s\" )\n", prefix, val, 0 );
182
183         realval = val;
184         tmpval = NULL;
185
186         if ( prefix != UNKNOWN_PREFIX ) {
187               unsigned int     len = strlen( val );
188
189               if ( (len + 2) < sizeof(buf) ) {
190                         realval = buf;
191                 } else {
192                         /* value + prefix + null */
193                         tmpval = (char *) ch_malloc( len + 2 );
194                         realval = tmpval;
195                 }
196               realval[0] = prefix;
197               strcpy( &realval[1], val );
198         }
199
200         key.dptr = realval;
201         key.dsize = strlen( realval ) + 1;
202
203         rc = idl_insert_key( be, db, key, id );
204
205         if ( tmpval != NULL ) {
206                 free( tmpval );
207         }
208
209         if( idl != NULL ) {
210                 idl_free( idl );
211         }
212
213         ldap_pvt_thread_yield();
214
215         /* Debug( LDAP_DEBUG_TRACE, "<= add_value %d\n", rc, 0, 0 ); */
216         return( rc );
217 }
218
219 int
220 index_add_values(
221     Backend             *be,
222     char                *type,
223     struct berval       **vals,
224     ID                  id
225 )
226 {
227         char            *val, *p, *code, *w;
228         unsigned        i, j, len;
229         int             indexmask, syntax;
230         char            buf[SUBLEN + 1];
231         char            vbuf[BUFSIZ];
232         char            *bigbuf;
233         struct dbcache  *db;
234
235         Debug( LDAP_DEBUG_TRACE, "=> index_add_values( \"%s\", %ld )\n", type,
236             id, 0 );
237         attr_normalize(type);
238         attr_masks( be->be_private, type, &indexmask, &syntax );
239         if ( indexmask == 0 ) {
240                 return( 0 );
241         }
242
243         if ( (db = ldbm_cache_open( be, type, LDBM_SUFFIX, LDBM_WRCREAT ))
244             == NULL ) {
245                 Debug( LDAP_DEBUG_ANY,
246                     "<= index_add_values -1 (could not open/create %s%s)\n",
247                     type, LDBM_SUFFIX, 0 );
248                 return( -1 );
249         }
250
251
252         for ( i = 0; vals[i] != NULL; i++ ) {
253                 /*
254                  * presence index entry
255                  */
256                 if ( indexmask & INDEX_PRESENCE ) {
257                         add_value( be, db, type, INDEX_PRESENCE, "*", id );
258                 }
259
260                 Debug( LDAP_DEBUG_TRACE, "*** index_add_values syntax 0x%x syntax bin 0x%x\n",
261                     syntax, SYNTAX_BIN, 0 );
262                 if ( syntax & SYNTAX_BIN ) {
263                         ldbm_cache_close( be, db );
264                         return( 0 );
265                 }
266
267                 bigbuf = NULL;
268                 len = vals[i]->bv_len;
269
270                 /* value + null */
271                 if ( len + 2 > sizeof(vbuf) ) {
272                         bigbuf = (char *) ch_malloc( len + 1 );
273                         val = bigbuf;
274                 } else {
275                         val = vbuf;
276                 }
277                 (void) memcpy( val, vals[i]->bv_val, len );
278                 val[len] = '\0';
279
280                 value_normalize( val, syntax );
281
282                 /*
283                  * equality index entry
284                  */
285                 if ( indexmask & INDEX_EQUALITY ) {
286                         add_value( be, db, type, INDEX_EQUALITY, val, id );
287                 }
288
289                 /*
290                  * approximate index entry
291                  */
292                 if ( indexmask & INDEX_APPROX ) {
293                         for ( w = first_word( val ); w != NULL;
294                             w = next_word( w ) ) {
295                                 if ( (code = phonetic( w )) != NULL ) {
296                                         add_value( be, db, type, INDEX_APPROX,
297                                             code, id );
298                                         free( code );
299                                 }
300                         }
301                 }
302
303                 /*
304                  * substrings index entry
305                  */
306                 if ( indexmask & INDEX_SUB ) {
307                         /* leading and trailing */
308                         if ( len > SUBLEN - 2 ) {
309                                 buf[0] = '^';
310                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
311                                         buf[j + 1] = val[j];
312                                 }
313                                 buf[SUBLEN] = '\0';
314
315                                 add_value( be, db, type, INDEX_SUB, buf, id );
316
317                                 p = val + len - SUBLEN + 1;
318                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
319                                         buf[j] = p[j];
320                                 }
321                                 buf[SUBLEN - 1] = '$';
322                                 buf[SUBLEN] = '\0';
323
324                                 add_value( be, db, type, INDEX_SUB, buf, id );
325                         }
326
327                         /* any */
328                         for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
329                                 for ( j = 0; j < SUBLEN; j++ ) {
330                                         buf[j] = p[j];
331                                 }
332                                 buf[SUBLEN] = '\0';
333
334                                 add_value( be, db, type, INDEX_SUB, buf, id );
335                         }
336                 }
337
338                 if ( bigbuf != NULL ) {
339                         free( bigbuf );
340                 }
341         }
342         ldbm_cache_close( be, db );
343
344         return( 0 );
345 }
346
347 static int
348 index2prefix( int indextype )
349 {
350         int     prefix;
351
352         switch ( indextype ) {
353         case INDEX_EQUALITY:
354                 prefix = EQ_PREFIX;
355                 break;
356         case INDEX_APPROX:
357                 prefix = APPROX_PREFIX;
358                 break;
359         case INDEX_SUB:
360                 prefix = SUB_PREFIX;
361                 break;
362         default:
363                 prefix = UNKNOWN_PREFIX;
364                 break;
365         }
366
367         return( prefix );
368 }