]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/index.c
703d9017b09c4f65247827870f328622f5c85b93
[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 ( at_cn == NULL ) {
152                 Debug( LDAP_DEBUG_ANY,
153                     "<= index_read no canonical name for type \"%s\"\n",
154                         type != NULL ? type : "(NULL)", 0, 0 );
155                 return( NULL );
156         }
157
158         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, LDBM_WRCREAT ))
159             == NULL ) {
160                 Debug( LDAP_DEBUG_ANY,
161                     "<= index_read NULL (could not open %s%s)\n",
162                         at_cn, LDBM_SUFFIX, 0 );
163                 return( NULL );
164         }
165
166         realval = val;
167         tmpval = NULL;
168         if ( prefix != UNKNOWN_PREFIX ) {
169                 unsigned int    len = strlen( val );
170
171                 if ( (len + 2) < sizeof(buf) ) {
172                         realval = buf;
173                 } else {
174                         /* value + prefix + null */
175                         tmpval = (char *) ch_malloc( len + 2 );
176                         realval = tmpval;
177                 }
178
179                 realval[0] = prefix;
180                 strcpy( &realval[1], val );
181         }
182
183         key.dptr = realval;
184         key.dsize = strlen( realval ) + 1;
185
186         idl = idl_fetch( be, db, key );
187         if ( tmpval != NULL ) {
188               free( tmpval );
189         }
190
191         ldbm_cache_close( be, db );
192
193         Debug( LDAP_DEBUG_TRACE, "<= index_read %ld candidates\n",
194                idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
195         return( idl );
196 }
197
198 /* Add or remove stuff from index files */
199
200 static int
201 change_value(
202     Backend             *be,
203     DBCache     *db,
204     char                *type,
205     int                 indextype,
206     char                *val,
207     ID                  id,
208     int                 (*idl_func)(Backend *, DBCache *, Datum, ID)
209 )
210 {
211         int     rc;
212         Datum   key;
213         char    *tmpval = NULL;
214         char    *realval = val;
215         char    buf[BUFSIZ];
216
217         char    prefix = index2prefix( indextype );
218
219         ldbm_datum_init( key );
220
221         Debug( LDAP_DEBUG_TRACE,
222                "=> change_value( \"%c%s\", op=%s )\n",
223                prefix, val, (idl_func == idl_insert_key ? "ADD":"DELETE") );
224
225         if ( prefix != UNKNOWN_PREFIX ) {
226               unsigned int     len = strlen( val );
227
228               if ( (len + 2) < sizeof(buf) ) {
229                         realval = buf;
230               } else {
231                         /* value + prefix + null */
232                         tmpval = (char *) ch_malloc( len + 2 );
233                         realval = tmpval;
234               }
235               realval[0] = prefix;
236               strcpy( &realval[1], val );
237         }
238
239         key.dptr = realval;
240         key.dsize = strlen( realval ) + 1;
241
242         rc = idl_func( be, db, key, id );
243
244         if ( tmpval != NULL ) {
245                 free( tmpval );
246         }
247
248         ldap_pvt_thread_yield();
249
250         Debug( LDAP_DEBUG_TRACE, "<= change_value %d\n", rc, 0, 0 );
251
252         return( rc );
253
254 }/* static int change_value() */
255
256
257 int
258 index_change_values(
259     Backend             *be,
260     char                *type,
261     struct berval       **vals,
262     ID                  id,
263     unsigned int        op
264 )
265 {
266         char            *val, *p, *code, *w;
267         unsigned        i, j, len;
268         int             indexmask, syntax;
269         char            buf[SUBLEN + 1];
270         char            vbuf[BUFSIZ];
271         char            *bigbuf;
272         DBCache *db;
273
274         int             (*idl_funct)(Backend *,
275                                     DBCache *,
276                                     Datum, ID);
277         char            *at_cn; /* Attribute canonical name */
278         int             mode;
279
280         if( vals == NULL ) {
281                 Debug( LDAP_DEBUG_TRACE,
282                         "=> index_change_values( %s, NULL, %ld, op=%s )\n", 
283                         type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
284                 return 0;
285         }
286
287         Debug( LDAP_DEBUG_TRACE,
288                "=> index_change_values( \"%s\", %ld, op=%s )\n", 
289                type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
290
291         
292         if (op == SLAP_INDEX_ADD_OP) {
293
294             /* Add values */
295
296             idl_funct =  idl_insert_key;
297             mode = LDBM_WRCREAT;
298
299         } else {
300
301             /* Delete values */
302
303             idl_funct = idl_delete_key;
304             mode = LDBM_WRITER;
305
306         }
307
308         attr_normalize(type);
309         attr_masks( be->be_private, type, &indexmask, &syntax );
310
311         if ( indexmask == 0 ) {
312                 return( 0 );
313         }
314
315         at_cn = at_canonical_name( type );
316
317         if ( at_cn == NULL ) {
318                 Debug( LDAP_DEBUG_ANY,
319                     "<= index_change_values no canonical name for type \"%s\"\n",
320                         type != NULL ? type : "(NULL)", 0, 0 );
321                 return( -1 );
322         }
323
324 #ifdef SLAPD_SCHEMA_COMPAT
325         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, mode ))
326              == NULL ) {
327                 Debug( LDAP_DEBUG_ANY,
328                        "<= index_change_values (couldn't open(%s%s),md=%s)\n",
329                        at_cn, LDBM_SUFFIX,
330                        ((mode==LDBM_WRCREAT)?"LDBM_WRCREAT":"LDBM_WRITER") );
331                 return( -1 );
332         }
333
334
335         for ( i = 0; vals[i] != NULL; i++ ) {
336                 /*
337                  * presence index entry
338                  */
339                 if ( indexmask & INDEX_PRESENCE ) {
340
341                         change_value( be, db, at_cn, INDEX_PRESENCE,
342                                       "*", id, idl_funct );
343
344                 }
345
346                 Debug( LDAP_DEBUG_TRACE,
347                        "index_change_values syntax 0x%x syntax bin 0x%x\n",
348                        syntax, SYNTAX_BIN, 0 );
349
350                 if ( syntax & SYNTAX_BIN ) {
351
352                         ldbm_cache_close( be, db );
353                         return( 0 );
354
355                 }
356
357                 bigbuf = NULL;
358                 len = vals[i]->bv_len;
359
360                 /* value + null */
361                 if ( len + 2 > sizeof(vbuf) ) {
362                         bigbuf = (char *) ch_malloc( len + 1 );
363                         val = bigbuf;
364                 } else {
365                         val = vbuf;
366                 }
367                 (void) memcpy( val, vals[i]->bv_val, len );
368                 val[len] = '\0';
369
370                 value_normalize( val, syntax );
371
372                 /* value_normalize could change the length of val */
373                 len = strlen( val );
374
375                 /*
376                  * equality index entry
377                  */
378                 if ( indexmask & INDEX_EQUALITY ) {
379                     
380                         change_value( be, db, at_cn, INDEX_EQUALITY,
381                                       val, id, idl_funct);
382
383                 }
384
385                 /*
386                  * approximate index entry
387                  */
388                 if ( indexmask & INDEX_APPROX ) {
389                         for ( w = first_word( val ); w != NULL;
390                             w = next_word( w ) ) {
391                                 if ( (code = phonetic( w )) != NULL ) {
392                                         change_value( be,
393                                                       db,
394                                                       at_cn,
395                                                       INDEX_APPROX,
396                                                       code,
397                                                       id,
398                                                       idl_funct );
399                                         free( code );
400                                 }
401                         }
402                 }
403
404                 /*
405                  * substrings index entry
406                  */
407                 if ( indexmask & INDEX_SUB ) {
408                         /* leading and trailing */
409                         if ( len > SUBLEN - 2 ) {
410                                 buf[0] = '^';
411                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
412                                         buf[j + 1] = val[j];
413                                 }
414                                 buf[SUBLEN] = '\0';
415
416                                 change_value( be, db, at_cn, INDEX_SUB,
417                                               buf, id, idl_funct );
418
419                                 p = val + len - SUBLEN + 1;
420                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
421                                         buf[j] = p[j];
422                                 }
423                                 buf[SUBLEN - 1] = '$';
424                                 buf[SUBLEN] = '\0';
425
426                                 change_value( be, db, at_cn, INDEX_SUB,
427                                               buf, id, idl_funct );
428                         }
429
430                         /* any */
431                         for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
432                                 for ( j = 0; j < SUBLEN; j++ ) {
433                                         buf[j] = p[j];
434                                 }
435                                 buf[SUBLEN] = '\0';
436
437                                 change_value( be, db, at_cn, INDEX_SUB,
438                                               buf, id, idl_funct );
439                         }
440                 }
441
442                 if ( bigbuf != NULL ) {
443                         free( bigbuf );
444                 }
445         }
446
447         ldbm_cache_close( be, db );
448 #endif
449
450         return( 0 );
451
452 }
453
454 static int
455 index2prefix( int indextype )
456 {
457         int     prefix;
458
459         switch ( indextype ) {
460         case INDEX_EQUALITY:
461                 prefix = EQ_PREFIX;
462                 break;
463         case INDEX_APPROX:
464                 prefix = APPROX_PREFIX;
465                 break;
466         case INDEX_SUB:
467                 prefix = SUB_PREFIX;
468                 break;
469         default:
470                 prefix = UNKNOWN_PREFIX;
471                 break;
472         }
473
474         return( prefix );
475 }