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