]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/index.c
debd1608fb79b11404ebe6e8efc50d2c1192b9c6
[openldap] / servers / slapd / back-ldbm / index.c
1 /* index.c - routines for dealing with attribute indexes */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/string.h>
12 #include <ac/socket.h>
13
14 #include "slap.h"
15 #include "back-ldbm.h"
16
17 static int      change_value(Backend *be,
18                           DBCache *db,
19                           char *type,
20                           int indextype,
21                           char *val,
22                           ID id,
23                           int
24                           (*idl_func)(Backend *, DBCache *, Datum, ID));
25 static int      index2prefix(int indextype);
26
27 int
28 index_add_entry(
29     Backend     *be,
30     Entry       *e
31 )
32 {
33         Attribute       *ap;
34         struct berval   bv;
35         struct berval   *bvals[2];
36
37         Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
38             e->e_dn, 0 );
39
40         /*
41          * dn index entry - make it look like an attribute so it works
42          * with index_change_values() call
43          */
44
45         bv.bv_val = ch_strdup( e->e_ndn );
46         bv.bv_len = strlen( bv.bv_val );
47         bvals[0] = &bv;
48         bvals[1] = NULL;
49
50         /* add the dn to the indexes */
51         {
52                 char *dn = ch_strdup("dn");
53                 index_change_values( be, dn, bvals, e->e_id, __INDEX_ADD_OP );
54                 free( dn );
55         }
56
57         free( bv.bv_val );
58
59         /* add each attribute to the indexes */
60         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
61
62                 index_change_values( be, ap->a_type, ap->a_vals, e->e_id,
63                                      __INDEX_ADD_OP );
64         }
65
66         Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
67             e->e_ndn, 0 );
68         return( 0 );
69 }
70
71 int
72 index_add_mods(
73     Backend     *be,
74     LDAPModList *ml,
75     ID          id
76 )
77 {
78         int     rc;
79
80         for ( ; ml != NULL; ml = ml->ml_next ) {
81                 LDAPMod *mod = &ml->ml_mod;
82
83                 switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
84                 case LDAP_MOD_REPLACE:
85                         /* XXX: Delete old index data==>problem when this 
86                          * gets called we lost values already!
87                          */
88                 case LDAP_MOD_ADD:
89                         rc = index_change_values( be,
90                                                mod->mod_type,
91                                                mod->mod_bvalues,
92                                                id,
93                                                __INDEX_ADD_OP);
94                         break;
95                 case LDAP_MOD_DELETE:
96                         rc =  index_change_values( be,
97                                                    mod->mod_type,
98                                                    mod->mod_bvalues,
99                                                    id,
100                                                    __INDEX_DELETE_OP );
101                         break;
102                 case LDAP_MOD_SOFTADD:  /* SOFTADD means index was there */
103                         rc = 0;
104                         break;
105                 }
106
107                 if ( rc != 0 ) {
108                         return( rc );
109                 }
110         }
111
112         return( 0 );
113 }
114
115 ID_BLOCK *
116 index_read(
117     Backend     *be,
118     char        *type,
119     int         indextype,
120     char        *val
121 )
122 {
123         DBCache *db;
124         Datum           key;
125         ID_BLOCK                *idl;
126         int             indexmask, syntax;
127         char            prefix;
128         char            *realval, *tmpval;
129         char            buf[BUFSIZ];
130
131         char            *at_cn;
132
133         ldbm_datum_init( key );
134
135         prefix = index2prefix( indextype );
136         Debug( LDAP_DEBUG_TRACE, "=> index_read( \"%s\" \"%c\" \"%s\" )\n",
137             type, prefix, val );
138
139         attr_masks( be->be_private, type, &indexmask, &syntax );
140         if ( ! (indextype & indexmask) ) {
141                 idl =  idl_allids( be );
142                 Debug( LDAP_DEBUG_TRACE,
143                     "<= index_read %ld candidates (allids - not indexed)\n",
144                     idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
145                 return( idl );
146         }
147
148         attr_normalize( type );
149         at_cn = at_canonical_name( type );
150
151         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, LDBM_WRCREAT ))
152             == NULL ) {
153                 Debug( LDAP_DEBUG_ANY,
154                     "<= index_read NULL (could not open %s%s)\n", at_cn,
155                     LDBM_SUFFIX, 0 );
156                 return( NULL );
157         }
158
159         realval = val;
160         tmpval = NULL;
161         if ( prefix != UNKNOWN_PREFIX ) {
162               unsigned int      len = strlen( val );
163
164               if ( (len + 2) < sizeof(buf) ) {
165                         realval = buf;
166                 } else {
167                         /* value + prefix + null */
168                         tmpval = (char *) ch_malloc( len + 2 );
169                         realval = tmpval;
170                 }
171               realval[0] = prefix;
172               strcpy( &realval[1], val );
173         }
174
175         key.dptr = realval;
176         key.dsize = strlen( realval ) + 1;
177
178         idl = idl_fetch( be, db, key );
179         if ( tmpval != NULL ) {
180               free( tmpval );
181         }
182
183         ldbm_cache_close( be, db );
184
185         Debug( LDAP_DEBUG_TRACE, "<= index_read %ld candidates\n",
186                idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
187         return( idl );
188 }
189
190 /* Add or remove stuff from index files */
191
192 static int
193 change_value(
194     Backend             *be,
195     DBCache     *db,
196     char                *type,
197     int                 indextype,
198     char                *val,
199     ID                  id,
200     int                 (*idl_func)(Backend *, DBCache *, Datum, ID)
201 )
202 {
203         int     rc;
204         Datum   key;
205         char    *tmpval = NULL;
206         char    *realval = val;
207         char    buf[BUFSIZ];
208
209         char    prefix = index2prefix( indextype );
210
211         ldbm_datum_init( key );
212
213         Debug( LDAP_DEBUG_TRACE,
214                "=> change_value( \"%c%s\", op=%s )\n",
215                prefix, val, (idl_func == idl_insert_key ? "ADD":"DELETE") );
216
217         if ( prefix != UNKNOWN_PREFIX ) {
218               unsigned int     len = strlen( val );
219
220               if ( (len + 2) < sizeof(buf) ) {
221                         realval = buf;
222               } else {
223                         /* value + prefix + null */
224                         tmpval = (char *) ch_malloc( len + 2 );
225                         realval = tmpval;
226               }
227               realval[0] = prefix;
228               strcpy( &realval[1], val );
229         }
230
231         key.dptr = realval;
232         key.dsize = strlen( realval ) + 1;
233
234         rc = idl_func( be, db, key, id );
235
236         if ( tmpval != NULL ) {
237                 free( tmpval );
238         }
239
240         ldap_pvt_thread_yield();
241
242         Debug( LDAP_DEBUG_TRACE, "<= change_value %d\n", rc, 0, 0 );
243
244         return( rc );
245
246 }/* static int change_value() */
247
248
249 int
250 index_change_values(
251     Backend             *be,
252     char                *type,
253     struct berval       **vals,
254     ID                  id,
255     unsigned int        op
256 )
257 {
258         char            *val, *p, *code, *w;
259         unsigned        i, j, len;
260         int             indexmask, syntax;
261         char            buf[SUBLEN + 1];
262         char            vbuf[BUFSIZ];
263         char            *bigbuf;
264         DBCache *db;
265
266         int             (*idl_funct)(Backend *,
267                                     DBCache *,
268                                     Datum, ID);
269         char            *at_cn; /* Attribute canonical name */
270         int             mode;
271
272         if( vals == NULL ) {
273                 Debug( LDAP_DEBUG_TRACE,
274                         "=> index_change_values( %s, NULL, %ld, op=%s )\n", 
275                         type, id, ((op == __INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
276                 return 0;
277         }
278
279         Debug( LDAP_DEBUG_TRACE,
280                "=> index_change_values( \"%s\", %ld, op=%s )\n", 
281                type, id, ((op == __INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
282
283         
284         if (op == __INDEX_ADD_OP) {
285
286             /* Add values */
287
288             idl_funct =  idl_insert_key;
289             mode = LDBM_WRCREAT;
290
291         } else {
292
293             /* Delete values */
294
295             idl_funct = idl_delete_key;
296             mode = LDBM_WRITER;
297
298         }
299
300         attr_normalize(type);
301         attr_masks( be->be_private, type, &indexmask, &syntax );
302
303         if ( indexmask == 0 ) {
304                 return( 0 );
305         }
306
307         at_cn = at_canonical_name( type );
308
309         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, mode ))
310              == NULL ) {
311                 Debug( LDAP_DEBUG_ANY,
312                        "<= index_change_values (couldn't open(%s%s),md=%s)\n",
313                        at_cn,
314                        LDBM_SUFFIX,
315                        ((mode==LDBM_WRCREAT)?"LDBM_WRCREAT":"LDBM_WRITER") );
316                 return( -1 );
317         }
318
319
320         for ( i = 0; vals[i] != NULL; i++ ) {
321                 /*
322                  * presence index entry
323                  */
324                 if ( indexmask & INDEX_PRESENCE ) {
325
326                         change_value( be, db, at_cn, INDEX_PRESENCE,
327                                       "*", id, idl_funct );
328
329                 }
330
331                 Debug( LDAP_DEBUG_TRACE,
332                        "index_change_values syntax 0x%x syntax bin 0x%x\n",
333                        syntax, SYNTAX_BIN, 0 );
334
335                 if ( syntax & SYNTAX_BIN ) {
336
337                         ldbm_cache_close( be, db );
338                         return( 0 );
339
340                 }
341
342                 bigbuf = NULL;
343                 len = vals[i]->bv_len;
344
345                 /* value + null */
346                 if ( len + 2 > sizeof(vbuf) ) {
347                         bigbuf = (char *) ch_malloc( len + 1 );
348                         val = bigbuf;
349                 } else {
350                         val = vbuf;
351                 }
352                 (void) memcpy( val, vals[i]->bv_val, len );
353                 val[len] = '\0';
354
355                 value_normalize( val, syntax );
356
357                 /* value_normalize could change the length of val */
358                 len = strlen( val );
359
360                 /*
361                  * equality index entry
362                  */
363                 if ( indexmask & INDEX_EQUALITY ) {
364                     
365                         change_value( be, db, at_cn, INDEX_EQUALITY,
366                                       val, id, idl_funct);
367
368                 }
369
370                 /*
371                  * approximate index entry
372                  */
373                 if ( indexmask & INDEX_APPROX ) {
374                         for ( w = first_word( val ); w != NULL;
375                             w = next_word( w ) ) {
376                                 if ( (code = phonetic( w )) != NULL ) {
377                                         change_value( be,
378                                                       db,
379                                                       at_cn,
380                                                       INDEX_APPROX,
381                                                       code,
382                                                       id,
383                                                       idl_funct );
384                                         free( code );
385                                 }
386                         }
387                 }
388
389                 /*
390                  * substrings index entry
391                  */
392                 if ( indexmask & INDEX_SUB ) {
393                         /* leading and trailing */
394                         if ( len > SUBLEN - 2 ) {
395                                 buf[0] = '^';
396                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
397                                         buf[j + 1] = val[j];
398                                 }
399                                 buf[SUBLEN] = '\0';
400
401                                 change_value( be, db, at_cn, INDEX_SUB,
402                                               buf, id, idl_funct );
403
404                                 p = val + len - SUBLEN + 1;
405                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
406                                         buf[j] = p[j];
407                                 }
408                                 buf[SUBLEN - 1] = '$';
409                                 buf[SUBLEN] = '\0';
410
411                                 change_value( be, db, at_cn, INDEX_SUB,
412                                               buf, id, idl_funct );
413                         }
414
415                         /* any */
416                         for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
417                                 for ( j = 0; j < SUBLEN; j++ ) {
418                                         buf[j] = p[j];
419                                 }
420                                 buf[SUBLEN] = '\0';
421
422                                 change_value( be, db, at_cn, INDEX_SUB,
423                                               buf, id, idl_funct );
424                         }
425                 }
426
427                 if ( bigbuf != NULL ) {
428                         free( bigbuf );
429                 }
430         }
431
432         ldbm_cache_close( be, db );
433
434         return( 0 );
435
436 }/* int index_change_values() */
437
438 static int
439 index2prefix( int indextype )
440 {
441         int     prefix;
442
443         switch ( indextype ) {
444         case INDEX_EQUALITY:
445                 prefix = EQ_PREFIX;
446                 break;
447         case INDEX_APPROX:
448                 prefix = APPROX_PREFIX;
449                 break;
450         case INDEX_SUB:
451                 prefix = SUB_PREFIX;
452                 break;
453         default:
454                 prefix = UNKNOWN_PREFIX;
455                 break;
456         }
457
458         return( prefix );
459 }