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