]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/index.c
12db542582c9d05017050f3ff771b1f21de44a80
[openldap] / servers / slapd / back-ldbm / index.c
1 /* index.c - routines for dealing with attribute indexes */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 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-ldbm.h"
17
18 static int      change_value(Backend *be,
19                           DBCache *db,
20                           char *type,
21                           int indextype,
22                           char *val,
23                           ID id,
24                           int
25                           (*idl_func)(Backend *, DBCache *, Datum, ID));
26 static int      index2prefix(int indextype);
27
28 int
29 index_add_entry(
30     Backend     *be,
31     Entry       *e
32 )
33 {
34         Attribute       *ap;
35         struct berval   bv;
36         struct berval   *bvals[2];
37
38         Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
39             e->e_dn, 0 );
40
41         /*
42          * dn index entry - make it look like an attribute so it works
43          * with index_change_values() call
44          */
45
46         bv.bv_val = ch_strdup( e->e_ndn );
47         bv.bv_len = strlen( bv.bv_val );
48         bvals[0] = &bv;
49         bvals[1] = NULL;
50
51         /* add the dn to the indexes */
52         {
53                 char *dn = ch_strdup("dn");
54                 index_change_values( be, dn, bvals, e->e_id, SLAP_INDEX_ADD_OP );
55                 free( dn );
56         }
57
58         free( bv.bv_val );
59
60         /* add each attribute to the indexes */
61         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
62                 index_change_values( be, ap->a_type, ap->a_vals, e->e_id,
63                                      SLAP_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                                                SLAP_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                                                    SLAP_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(\"%c%s\"->\"%s\")\n",
137             prefix, type, 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
172                 realval[0] = prefix;
173                 strcpy( &realval[1], val );
174         }
175
176         key.dptr = realval;
177         key.dsize = strlen( realval ) + 1;
178
179         idl = idl_fetch( be, db, key );
180         if ( tmpval != NULL ) {
181               free( tmpval );
182         }
183
184         ldbm_cache_close( be, db );
185
186         Debug( LDAP_DEBUG_TRACE, "<= index_read %ld candidates\n",
187                idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
188         return( idl );
189 }
190
191 /* Add or remove stuff from index files */
192
193 static int
194 change_value(
195     Backend             *be,
196     DBCache     *db,
197     char                *type,
198     int                 indextype,
199     char                *val,
200     ID                  id,
201     int                 (*idl_func)(Backend *, DBCache *, Datum, ID)
202 )
203 {
204         int     rc;
205         Datum   key;
206         char    *tmpval = NULL;
207         char    *realval = val;
208         char    buf[BUFSIZ];
209
210         char    prefix = index2prefix( indextype );
211
212         ldbm_datum_init( key );
213
214         Debug( LDAP_DEBUG_TRACE,
215                "=> change_value( \"%c%s\", op=%s )\n",
216                prefix, val, (idl_func == idl_insert_key ? "ADD":"DELETE") );
217
218         if ( prefix != UNKNOWN_PREFIX ) {
219               unsigned int     len = strlen( val );
220
221               if ( (len + 2) < sizeof(buf) ) {
222                         realval = buf;
223               } else {
224                         /* value + prefix + null */
225                         tmpval = (char *) ch_malloc( len + 2 );
226                         realval = tmpval;
227               }
228               realval[0] = prefix;
229               strcpy( &realval[1], val );
230         }
231
232         key.dptr = realval;
233         key.dsize = strlen( realval ) + 1;
234
235         rc = idl_func( be, db, key, id );
236
237         if ( tmpval != NULL ) {
238                 free( tmpval );
239         }
240
241         ldap_pvt_thread_yield();
242
243         Debug( LDAP_DEBUG_TRACE, "<= change_value %d\n", rc, 0, 0 );
244
245         return( rc );
246
247 }/* static int change_value() */
248
249
250 int
251 index_change_values(
252     Backend             *be,
253     char                *type,
254     struct berval       **vals,
255     ID                  id,
256     unsigned int        op
257 )
258 {
259         char            *val, *p, *code, *w;
260         unsigned        i, j, len;
261         int             indexmask, syntax;
262         char            buf[SUBLEN + 1];
263         char            vbuf[BUFSIZ];
264         char            *bigbuf;
265         DBCache *db;
266
267         int             (*idl_funct)(Backend *,
268                                     DBCache *,
269                                     Datum, ID);
270         char            *at_cn; /* Attribute canonical name */
271         int             mode;
272
273         if( vals == NULL ) {
274                 Debug( LDAP_DEBUG_TRACE,
275                         "=> index_change_values( %s, NULL, %ld, op=%s )\n", 
276                         type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
277                 return 0;
278         }
279
280         Debug( LDAP_DEBUG_TRACE,
281                "=> index_change_values( \"%s\", %ld, op=%s )\n", 
282                type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
283
284         
285         if (op == SLAP_INDEX_ADD_OP) {
286
287             /* Add values */
288
289             idl_funct =  idl_insert_key;
290             mode = LDBM_WRCREAT;
291
292         } else {
293
294             /* Delete values */
295
296             idl_funct = idl_delete_key;
297             mode = LDBM_WRITER;
298
299         }
300
301         attr_normalize(type);
302         attr_masks( be->be_private, type, &indexmask, &syntax );
303
304         if ( indexmask == 0 ) {
305                 return( 0 );
306         }
307
308         at_cn = at_canonical_name( type );
309
310         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, mode ))
311              == NULL ) {
312                 Debug( LDAP_DEBUG_ANY,
313                        "<= index_change_values (couldn't open(%s%s),md=%s)\n",
314                        at_cn,
315                        LDBM_SUFFIX,
316                        ((mode==LDBM_WRCREAT)?"LDBM_WRCREAT":"LDBM_WRITER") );
317                 return( -1 );
318         }
319
320
321         for ( i = 0; vals[i] != NULL; i++ ) {
322                 /*
323                  * presence index entry
324                  */
325                 if ( indexmask & INDEX_PRESENCE ) {
326
327                         change_value( be, db, at_cn, INDEX_PRESENCE,
328                                       "*", id, idl_funct );
329
330                 }
331
332                 Debug( LDAP_DEBUG_TRACE,
333                        "index_change_values syntax 0x%x syntax bin 0x%x\n",
334                        syntax, SYNTAX_BIN, 0 );
335
336                 if ( syntax & SYNTAX_BIN ) {
337
338                         ldbm_cache_close( be, db );
339                         return( 0 );
340
341                 }
342
343                 bigbuf = NULL;
344                 len = vals[i]->bv_len;
345
346                 /* value + null */
347                 if ( len + 2 > sizeof(vbuf) ) {
348                         bigbuf = (char *) ch_malloc( len + 1 );
349                         val = bigbuf;
350                 } else {
351                         val = vbuf;
352                 }
353                 (void) memcpy( val, vals[i]->bv_val, len );
354                 val[len] = '\0';
355
356                 value_normalize( val, syntax );
357
358                 /* value_normalize could change the length of val */
359                 len = strlen( val );
360
361                 /*
362                  * equality index entry
363                  */
364                 if ( indexmask & INDEX_EQUALITY ) {
365                     
366                         change_value( be, db, at_cn, INDEX_EQUALITY,
367                                       val, id, idl_funct);
368
369                 }
370
371                 /*
372                  * approximate index entry
373                  */
374                 if ( indexmask & INDEX_APPROX ) {
375                         for ( w = first_word( val ); w != NULL;
376                             w = next_word( w ) ) {
377                                 if ( (code = phonetic( w )) != NULL ) {
378                                         change_value( be,
379                                                       db,
380                                                       at_cn,
381                                                       INDEX_APPROX,
382                                                       code,
383                                                       id,
384                                                       idl_funct );
385                                         free( code );
386                                 }
387                         }
388                 }
389
390                 /*
391                  * substrings index entry
392                  */
393                 if ( indexmask & INDEX_SUB ) {
394                         /* leading and trailing */
395                         if ( len > SUBLEN - 2 ) {
396                                 buf[0] = '^';
397                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
398                                         buf[j + 1] = val[j];
399                                 }
400                                 buf[SUBLEN] = '\0';
401
402                                 change_value( be, db, at_cn, INDEX_SUB,
403                                               buf, id, idl_funct );
404
405                                 p = val + len - SUBLEN + 1;
406                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
407                                         buf[j] = p[j];
408                                 }
409                                 buf[SUBLEN - 1] = '$';
410                                 buf[SUBLEN] = '\0';
411
412                                 change_value( be, db, at_cn, INDEX_SUB,
413                                               buf, id, idl_funct );
414                         }
415
416                         /* any */
417                         for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
418                                 for ( j = 0; j < SUBLEN; j++ ) {
419                                         buf[j] = p[j];
420                                 }
421                                 buf[SUBLEN] = '\0';
422
423                                 change_value( be, db, at_cn, INDEX_SUB,
424                                               buf, id, idl_funct );
425                         }
426                 }
427
428                 if ( bigbuf != NULL ) {
429                         free( bigbuf );
430                 }
431         }
432
433         ldbm_cache_close( be, db );
434
435         return( 0 );
436
437 }
438
439 static int
440 index2prefix( int indextype )
441 {
442         int     prefix;
443
444         switch ( indextype ) {
445         case INDEX_EQUALITY:
446                 prefix = EQ_PREFIX;
447                 break;
448         case INDEX_APPROX:
449                 prefix = APPROX_PREFIX;
450                 break;
451         case INDEX_SUB:
452                 prefix = SUB_PREFIX;
453                 break;
454         default:
455                 prefix = UNKNOWN_PREFIX;
456                 break;
457         }
458
459         return( prefix );
460 }