]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/index.c
Prepare for unifdef -DSLAPD_SCHEMA_NOT_COMPAT
[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 #ifdef SLAPD_SCHEMA_NOT_COMPAT
19 static index_mask(
20         Backend *be,
21         AttributeDescription *desc,
22         char **dbname,
23         char **atname )
24 {
25         AttributeType *at;
26         slap_index mask = 0;
27
28         /* we do support indexing of binary attributes */
29         if( slap_ad_is_binary( desc ) ) return 0;
30
31         attr_mask( be->be_private, desc->ad_cname->bv_val, &mask );
32
33         if( mask ) {
34                 *atname = desc->ad_cname->bv_val;
35                 *dbname = desc->ad_cname->bv_val;
36                 return mask;
37         }
38
39         if( slap_ad_is_lang( desc ) ) {
40                 /* has language tag */
41                 attr_mask( be->be_private, desc->ad_type->sat_cname, &mask );
42
43                 if( mask & SLAP_INDEX_AUTO_LANG ) {
44                         *atname = desc->ad_cname->bv_val;
45                         *dbname = desc->ad_type->sat_cname;
46                         return mask;
47                 }
48                 if( mask & SLAP_INDEX_LANG ) {
49                         *atname = desc->ad_type->sat_cname;
50                         *dbname = desc->ad_type->sat_cname;
51                         return mask;
52                 }
53         }
54
55         /* see if supertype defined mask for its subtypes */
56         for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
57                 attr_mask( be->be_private, at->sat_cname, &mask );
58
59                 if( mask & SLAP_INDEX_AUTO_SUBTYPES ) {
60                         *atname = desc->ad_type->sat_cname;
61                         *dbname = at->sat_cname;
62                         return mask;
63                 }
64                 if( mask & SLAP_INDEX_SUBTYPES ) {
65                         *atname = at->sat_cname;
66                         *dbname = at->sat_cname;
67                         return mask;
68                 }
69
70                 if( mask ) break;
71         }
72
73         return 0;
74 }
75
76 int index_param(
77         Backend *be,
78         AttributeDescription *desc,
79         int ftype,
80         char **dbnamep,
81         slap_index *maskp,
82         struct berval **prefixp )
83 {
84         slap_index mask;
85         char *dbname;
86         char *atname;
87
88         mask = index_mask( be, desc, &dbname, &atname );
89
90         if( mask == 0 ) {
91                 return LDAP_INAPPROPRIATE_MATCHING;
92         }
93
94         switch(ftype) {
95         case LDAP_FILTER_PRESENT:
96                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
97                         goto done;
98                 }
99                 break;
100
101         case LDAP_FILTER_APPROX:
102                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
103                         goto done;
104                 }
105                 /* fall thru */
106
107         case LDAP_FILTER_EQUALITY:
108                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
109                         goto done;
110                 }
111                 break;
112
113         case LDAP_FILTER_SUBSTRINGS:
114                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
115                         goto done;
116                 }
117                 break;
118
119         default:
120                 return LDAP_OTHER;
121         }
122
123         return LDAP_INAPPROPRIATE_MATCHING;
124
125 done:
126         *dbnamep = dbname;
127         *prefixp = ber_bvstrdup( atname );
128         *maskp = mask;
129         return LDAP_SUCCESS;
130 }
131
132 static int indexer(
133         Backend *be,
134         char *dbname,
135         char *atname,
136         struct berval **vals,
137         ID id,
138         int op,
139         slap_index mask )
140 {
141         int rc, i;
142         const char *text;
143     DBCache     *db;
144         AttributeDescription *ad = NULL;
145         struct berval **keys;
146         struct berval prefix;
147
148         assert( mask );
149
150         rc = slap_str2ad( atname, &ad, &text );
151
152         if( rc != LDAP_SUCCESS ) return rc;
153
154         prefix.bv_val = atname;
155         prefix.bv_len = strlen( atname );
156
157         db = ldbm_cache_open( be, dbname, LDBM_SUFFIX, LDBM_WRCREAT );
158         
159         if ( db == NULL ) {
160                 Debug( LDAP_DEBUG_ANY,
161                     "<= index_read NULL (could not open %s%s)\n",
162                         dbname, LDBM_SUFFIX, 0 );
163                 ad_free( ad, 1 );
164                 return LDAP_OTHER;
165         }
166
167         if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
168                 key_change( be, db, &prefix, id, op );
169         }
170
171         if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
172                 rc = ad->ad_type->sat_equality->smr_indexer(
173                         mask,
174                         ad->ad_type->sat_syntax,
175                         ad->ad_type->sat_equality,
176                         &prefix, vals, &keys );
177
178                 if( rc == LDAP_SUCCESS ) {
179                         for( i= 0; keys[i] != NULL; i++ ) {
180                                 key_change( be, db, keys[i], id, op );
181                         }
182                 }
183         }
184
185         if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
186                 rc = ad->ad_type->sat_approx->smr_indexer(
187                         mask,
188                         ad->ad_type->sat_syntax,
189                         ad->ad_type->sat_approx,
190                         &prefix, vals, &keys );
191
192                 if( rc == LDAP_SUCCESS ) {
193                         for( i= 0; keys[i] != NULL; i++ ) {
194                                 key_change( be, db, keys[i], id, op );
195                         }
196                 }
197         }
198
199         if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
200                 rc = ad->ad_type->sat_substr->smr_indexer(
201                         mask,
202                         ad->ad_type->sat_syntax,
203                         ad->ad_type->sat_substr,
204                         &prefix, vals, &keys );
205
206                 if( rc == LDAP_SUCCESS ) {
207                         for( i= 0; keys[i] != NULL; i++ ) {
208                                 key_change( be, db, keys[i], id, op );
209                         }
210                 }
211         }
212
213         ldbm_cache_close( be, db );
214         ad_free( ad, 1 );
215         return LDAP_SUCCESS;
216 }
217
218 static int index_at_values(
219         Backend *be,
220         AttributeType *type,
221         const char *lang,
222         struct berval **vals,
223         ID id,
224         int op,
225         char ** dbnamep,
226         slap_index *maskp )
227 {
228         slap_index mask;
229         slap_index tmpmask = 0;
230         int lindex = 0;
231
232         if( type->sat_sup ) {
233                 /* recurse */
234                 (void) index_at_values( be,
235                         type->sat_sup, lang,
236                         vals, id, op,
237                         dbnamep, &tmpmask );
238         }
239
240         attr_mask( be->be_private, type->sat_cname, &mask );
241
242         if( mask ) {
243                 *dbnamep = type->sat_cname;
244         } else if ( tmpmask & SLAP_INDEX_AUTO_SUBTYPES ) {
245                 mask = tmpmask;
246         }
247
248         if( mask ) {
249                 indexer( be, *dbnamep,
250                         type->sat_cname,
251                         vals, id, op,
252                         mask );
253         }
254
255         if( lang ) {
256                 char *dbname = NULL;
257                 size_t tlen = strlen( type->sat_cname );
258                 size_t llen = strlen( lang );
259                 char *lname = ch_malloc( tlen + llen + sizeof(";") );
260
261                 sprintf( lname, "%s;%s", type->sat_cname, lang );
262
263                 attr_mask( be->be_private, lname, &tmpmask );
264
265                 if( tmpmask ) {
266                         dbname = lname;
267                 } else if ( mask & SLAP_INDEX_AUTO_LANG ) {
268                         dbname = *dbnamep;
269                         tmpmask = mask;
270                 }
271
272                 if( dbname != NULL ) {
273                         indexer( be, dbname, lname,
274                                 vals, id, op,
275                                 tmpmask );
276                 }
277
278                 ch_free( lname );
279         }
280
281         return LDAP_SUCCESS;
282 }
283
284 int index_values(
285         Backend *be,
286         AttributeDescription *desc,
287         struct berval **vals,
288         ID id,
289         int op )
290 {
291         char *dbname = NULL;
292         slap_index mask;
293
294         if( slap_ad_is_binary( desc ) ) {
295                 /* binary attributes have no index capabilities */
296                 return LDAP_SUCCESS;
297         }
298
299         (void) index_at_values( be,
300                 desc->ad_type, desc->ad_lang,
301                 vals, id, op,
302                 &dbname, &mask );
303
304         return LDAP_SUCCESS;
305 }
306
307 #else
308 int index_change_values(
309     Backend             *be,
310 #ifdef SLAPD_SCHEMA_NOT_COMPAT
311         AttributeDescription *desc,
312 #else
313     char                *desc,
314 #endif
315     struct berval       **vals,
316     ID                  id,
317     unsigned int        op
318 );
319
320 #ifndef SLAPD_SCHEMA_NOT_COMPAT
321 static int      change_value(Backend *be,
322         DBCache *db,
323         char *type,
324         int indextype,
325         char *val,
326         ID id,
327         int
328         (*idl_func)(Backend *, DBCache *, Datum, ID));
329 #endif
330 #endif
331
332 int
333 index_entry(
334     Backend     *be,
335         int op,
336     Entry       *e,
337         Attribute *ap
338 )
339 {
340 #ifndef SLAPD_SCHEMA_NOT_COMPAT
341         struct berval   bv;
342         struct berval   *bvals[2];
343 #endif
344
345         Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
346                 op == SLAP_INDEX_ADD_OP ? "add" : "del",
347                 e->e_id, e->e_dn );
348
349 #ifndef SLAPD_SCHEMA_NOT_COMPAT
350         /*
351          * dn index entry - make it look like an attribute so it works
352          * with index_change_values() call
353          */
354
355         bv.bv_val = ch_strdup( e->e_ndn );
356         bv.bv_len = strlen( bv.bv_val );
357         bvals[0] = &bv;
358         bvals[1] = NULL;
359
360         /* add the dn to the indexes */
361         {
362                 char *dn = ch_strdup("dn");
363                 index_change_values( be, dn, bvals, e->e_id, op );
364                 free( dn );
365         }
366
367         free( bv.bv_val );
368 #endif
369
370         /* add each attribute to the indexes */
371         for ( ap; ap != NULL; ap = ap->a_next ) {
372 #ifdef SLAPD_SCHEMA_NOT_COMPAT
373                 index_values( be, ap->a_desc, ap->a_vals, e->e_id, op );
374 #else
375                 index_change_values( be, ap->a_type, ap->a_vals, e->e_id, op );
376 #endif
377         }
378
379         Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
380             op == SLAP_INDEX_ADD_OP ? "add" : "del",
381                 e->e_id, e->e_dn );
382
383         return LDAP_SUCCESS;
384 }
385
386 #ifndef SLAPD_SCHEMA_NOT_COMPAT
387
388 ID_BLOCK *
389 index_read(
390     Backend     *be,
391     char        *type,
392     int         indextype,
393     char *val
394 )
395 {
396         DBCache *db;
397         Datum           key;
398         ID_BLOCK                *idl;
399         int             indexmask;
400         char            prefix;
401         char            *realval, *tmpval;
402         char            buf[BUFSIZ];
403
404         char            *at_cn;
405
406         ldbm_datum_init( key );
407
408         prefix = slap_index2prefix( indextype );
409         Debug( LDAP_DEBUG_TRACE, "=> index_read(\"%c%s\"->\"%s\")\n",
410             prefix, type, val );
411
412         attr_mask( be->be_private, type, &indexmask );
413         if ( ! (indextype & indexmask) ) {
414                 idl =  idl_allids( be );
415                 Debug( LDAP_DEBUG_TRACE,
416                     "<= index_read %ld candidates (allids - not indexed)\n",
417                     idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
418                 return( idl );
419         }
420
421 #ifdef SLAPD_SCHEMA_NOT_COMPAT
422         at_cn = at_canonical_name( at_find( type ) );
423 #else
424         attr_normalize( type );
425         at_cn = at_canonical_name( type );
426 #endif
427
428         if ( at_cn == NULL ) {
429                 Debug( LDAP_DEBUG_ANY,
430                     "<= index_read no canonical name for type \"%s\"\n",
431                         type != NULL ? type : "(NULL)", 0, 0 );
432                 return( NULL );
433         }
434
435         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, LDBM_WRCREAT ))
436             == NULL ) {
437                 Debug( LDAP_DEBUG_ANY,
438                     "<= index_read NULL (could not open %s%s)\n",
439                         at_cn, LDBM_SUFFIX, 0 );
440                 return( NULL );
441         }
442
443         realval = val;
444         tmpval = NULL;
445         if ( prefix != UNKNOWN_PREFIX ) {
446                 unsigned int    len = strlen( val );
447
448                 if ( (len + 2) < sizeof(buf) ) {
449                         realval = buf;
450                 } else {
451                         /* value + prefix + null */
452                         tmpval = (char *) ch_malloc( len + 2 );
453                         realval = tmpval;
454                 }
455
456                 realval[0] = prefix;
457                 strcpy( &realval[1], val );
458         }
459
460         key.dptr = realval;
461         key.dsize = strlen( realval ) + 1;
462
463         idl = idl_fetch( be, db, key );
464         if ( tmpval != NULL ) {
465               free( tmpval );
466         }
467
468         ldbm_cache_close( be, db );
469
470         Debug( LDAP_DEBUG_TRACE, "<= index_read %ld candidates\n",
471                idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
472         return( idl );
473 }
474
475 /* Add or remove stuff from index files */
476
477 static int
478 change_value(
479     Backend             *be,
480     DBCache     *db,
481     char                *type,
482     int                 indextype,
483     char                *val,
484     ID                  id,
485     int                 (*idl_func)(Backend *, DBCache *, Datum, ID)
486 )
487 {
488         int     rc;
489         Datum   key;
490         char    *tmpval = NULL;
491         char    *realval = val;
492         char    buf[BUFSIZ];
493
494         char    prefix = slap_index2prefix( indextype );
495
496         ldbm_datum_init( key );
497
498         Debug( LDAP_DEBUG_TRACE,
499                "=> change_value( \"%c%s\", op=%s )\n",
500                prefix, val, (idl_func == idl_insert_key ? "ADD":"DELETE") );
501
502         if ( prefix != UNKNOWN_PREFIX ) {
503               unsigned int     len = strlen( val );
504
505               if ( (len + 2) < sizeof(buf) ) {
506                         realval = buf;
507               } else {
508                         /* value + prefix + null */
509                         tmpval = (char *) ch_malloc( len + 2 );
510                         realval = tmpval;
511               }
512               realval[0] = prefix;
513               strcpy( &realval[1], val );
514         }
515
516         key.dptr = realval;
517         key.dsize = strlen( realval ) + 1;
518
519         rc = idl_func( be, db, key, id );
520
521         if ( tmpval != NULL ) {
522                 free( tmpval );
523         }
524
525         ldap_pvt_thread_yield();
526
527         Debug( LDAP_DEBUG_TRACE, "<= change_value %d\n", rc, 0, 0 );
528
529         return( rc );
530
531 }
532
533 #ifdef SLAPD_SCHEMA_NOT_COMPAT
534 static
535 #endif
536 int
537 index_change_values(
538     Backend             *be,
539 #ifdef SLAPD_SCHEMA_NOT_COMPAT
540         AttributeDescription *desc,
541 #else
542     char                *desc,
543 #endif
544     struct berval       **vals,
545     ID                  id,
546     unsigned int        op
547 )
548 {
549         char            *val, *p, *code, *w;
550         unsigned        i, j, len;
551         int             indexmask, syntax;
552         char            buf[SUBLEN + 1];
553         char            vbuf[BUFSIZ];
554         char            *bigbuf;
555         DBCache *db;
556
557         int             (*idl_funct)(Backend *,
558                                     DBCache *,
559                                     Datum, ID);
560         char            *at_cn; /* Attribute canonical name */
561         int             mode;
562
563 #ifdef SLAPD_SCHEMA_NOT_COMPAT
564         char *type = desc->ad_cname->bv_val;
565 #else
566         char *type = desc;
567 #endif
568
569         if( vals == NULL ) {
570                 Debug( LDAP_DEBUG_TRACE,
571                         "=> index_change_values( %s, NULL, %ld, op=%s )\n", 
572                         type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
573                 return 0;
574         }
575
576         Debug( LDAP_DEBUG_TRACE,
577                "=> index_change_values( \"%s\", %ld, op=%s )\n", 
578                type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
579
580         
581         if (op == SLAP_INDEX_ADD_OP) {
582             /* Add values */
583             idl_funct =  idl_insert_key;
584             mode = LDBM_WRCREAT;
585
586         } else {
587             /* Delete values */
588             idl_funct = idl_delete_key;
589             mode = LDBM_WRITER;
590         }
591
592 #ifndef SLAPD_SCHEMA_NOT_COMPAT
593         attr_normalize(type);
594 #endif
595         attr_mask( be->be_private, desc, &indexmask );
596
597         if ( indexmask == 0 ) {
598                 return( 0 );
599         }
600
601 #ifdef SLAPD_SCHEMA_NOT_COMPAT
602         at_cn = at_canonical_name( at_find( type ) );
603 #else
604         syntax = attr_syntax( type );
605         at_cn = at_canonical_name( type );
606 #endif
607
608         if ( at_cn == NULL ) {
609                 Debug( LDAP_DEBUG_ANY,
610                     "<= index_change_values no canonical name for type \"%s\"\n",
611                         type != NULL ? type : "(NULL)", 0, 0 );
612                 return( -1 );
613         }
614
615         if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, mode ))
616              == NULL ) {
617                 Debug( LDAP_DEBUG_ANY,
618                        "<= index_change_values (couldn't open(%s%s),md=%s)\n",
619                        at_cn, LDBM_SUFFIX,
620                        ((mode==LDBM_WRCREAT)?"LDBM_WRCREAT":"LDBM_WRITER") );
621                 return( -1 );
622         }
623
624         /*
625          * presence index entry
626          */
627         if ( indexmask & SLAP_INDEX_PRESENT ) {
628                 change_value( be, db, at_cn, SLAP_INDEX_PRESENT,
629                         "*", id, idl_funct );
630         }
631
632 #ifndef SLAPD_SCHEMA_NOT_COMPAT
633         if ( syntax & SYNTAX_BIN ) {
634                 goto done;
635         }
636 #endif
637
638         for ( i = 0; vals[i] != NULL; i++ ) {
639                 Debug( LDAP_DEBUG_TRACE,
640                        "index_change_values syntax 0x%x\n",
641                        syntax, 0, 0 );
642
643                 bigbuf = NULL;
644                 len = vals[i]->bv_len;
645
646                 /* value + null */
647                 if ( len + 2 > sizeof(vbuf) ) {
648                         bigbuf = (char *) ch_malloc( len + 1 );
649                         val = bigbuf;
650                 } else {
651                         val = vbuf;
652                 }
653                 (void) memcpy( val, vals[i]->bv_val, len );
654                 val[len] = '\0';
655
656 #ifndef SLAPD_SCHEMA_NOT_COMPAT
657                 value_normalize( val, syntax );
658 #endif
659
660                 /* value_normalize could change the length of val */
661                 len = strlen( val );
662
663                 /*
664                  * equality index entry
665                  */
666                 if ( indexmask & SLAP_INDEX_EQUALITY ) {
667                         change_value( be, db, at_cn, SLAP_INDEX_EQUALITY,
668                                       val, id, idl_funct);
669                 }
670
671                 /*
672                  * approximate index entry
673                  */
674                 if ( indexmask & SLAP_INDEX_APPROX ) {
675                         for ( w = first_word( val ); w != NULL;
676                             w = next_word( w ) ) {
677                                 if ( (code = phonetic( w )) != NULL ) {
678                                         change_value( be,
679                                                       db,
680                                                       at_cn,
681                                                       SLAP_INDEX_APPROX,
682                                                       code,
683                                                       id,
684                                                       idl_funct );
685                                         free( code );
686                                 }
687                         }
688                 }
689
690                 /*
691                  * substrings index entry
692                  */
693                 if ( indexmask & SLAP_INDEX_SUBSTR ) {
694                         /* leading and trailing */
695                         if ( len > SUBLEN - 2 ) {
696                                 buf[0] = '^';
697                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
698                                         buf[j + 1] = val[j];
699                                 }
700                                 buf[SUBLEN] = '\0';
701
702                                 change_value( be, db, at_cn, SLAP_INDEX_SUBSTR,
703                                               buf, id, idl_funct );
704
705                                 p = val + len - SUBLEN + 1;
706                                 for ( j = 0; j < SUBLEN - 1; j++ ) {
707                                         buf[j] = p[j];
708                                 }
709                                 buf[SUBLEN - 1] = '$';
710                                 buf[SUBLEN] = '\0';
711
712                                 change_value( be, db, at_cn, SLAP_INDEX_SUBSTR,
713                                               buf, id, idl_funct );
714                         }
715
716                         /* any */
717                         for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
718                                 for ( j = 0; j < SUBLEN; j++ ) {
719                                         buf[j] = p[j];
720                                 }
721                                 buf[SUBLEN] = '\0';
722
723                                 change_value( be, db, at_cn, SLAP_INDEX_SUBSTR,
724                                               buf, id, idl_funct );
725                         }
726                 }
727
728                 if ( bigbuf != NULL ) {
729                         free( bigbuf );
730                 }
731         }
732 #ifndef SLAPD_SCHEMA_NOT_COMPAT
733 done:
734 #endif
735         ldbm_cache_close( be, db );
736         return LDAP_SUCCESS;
737 }
738 #endif