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