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