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