]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/attr.c
Fix send_search_reference in prev commit
[openldap] / servers / slapd / back-bdb / attr.c
1 /* attr.c - backend routines for dealing with attributes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/socket.h>
22 #include <ac/string.h>
23
24 #include "slap.h"
25 #include "back-bdb.h"
26 #include "lutil.h"
27
28 /* Find the ad, return -1 if not found,
29  * set point for insertion if ins is non-NULL
30  */
31 int
32 bdb_attr_slot( struct bdb_info *bdb, AttributeDescription *ad, unsigned *ins )
33 {
34         unsigned base = 0, cursor = 0;
35         unsigned n = bdb->bi_nattrs;
36         int val = 0;
37         
38         while ( 0 < n ) {
39                 int pivot = n >> 1;
40                 cursor = base + pivot;
41
42                 val = SLAP_PTRCMP( ad, bdb->bi_attrs[cursor]->ai_desc );
43                 if ( val < 0 ) {
44                         n = pivot;
45                 } else if ( val > 0 ) {
46                         base = cursor + 1;
47                         n -= pivot + 1;
48                 } else {
49                         return cursor;
50                 }
51         }
52         if ( ins ) {
53                 if ( val > 0 )
54                         ++cursor;
55                 *ins = cursor;
56         }
57         return -1;
58 }
59
60 static int
61 ainfo_insert( struct bdb_info *bdb, AttrInfo *a )
62 {
63         unsigned x;
64         int i = bdb_attr_slot( bdb, a->ai_desc, &x );
65
66         /* Is it a dup? */
67         if ( i >= 0 )
68                 return -1;
69
70         bdb->bi_attrs = ch_realloc( bdb->bi_attrs, ( bdb->bi_nattrs+1 ) * 
71                 sizeof( AttrInfo * ));
72         if ( x < bdb->bi_nattrs )
73                 AC_MEMCPY( &bdb->bi_attrs[x+1], &bdb->bi_attrs[x],
74                         ( bdb->bi_nattrs - x ) * sizeof( AttrInfo *));
75         bdb->bi_attrs[x] = a;
76         bdb->bi_nattrs++;
77         return 0;
78 }
79
80 AttrInfo *
81 bdb_attr_mask(
82         struct bdb_info *bdb,
83         AttributeDescription *desc )
84 {
85         int i = bdb_attr_slot( bdb, desc, NULL );
86         return i < 0 ? NULL : bdb->bi_attrs[i];
87 }
88
89 int
90 bdb_attr_index_config(
91         struct bdb_info *bdb,
92         const char              *fname,
93         int                     lineno,
94         int                     argc,
95         char            **argv )
96 {
97         int rc;
98         int     i;
99         slap_mask_t mask;
100         char **attrs;
101         char **indexes = NULL;
102
103         attrs = ldap_str2charray( argv[0], "," );
104
105         if( attrs == NULL ) {
106                 fprintf( stderr, "%s: line %d: "
107                         "no attributes specified: %s\n",
108                         fname, lineno, argv[0] );
109                 return LDAP_PARAM_ERROR;
110         }
111
112         if ( argc > 1 ) {
113                 indexes = ldap_str2charray( argv[1], "," );
114
115                 if( indexes == NULL ) {
116                         fprintf( stderr, "%s: line %d: "
117                                 "no indexes specified: %s\n",
118                                 fname, lineno, argv[1] );
119                         return LDAP_PARAM_ERROR;
120                 }
121         }
122
123         if( indexes == NULL ) {
124                 mask = bdb->bi_defaultmask;
125
126         } else {
127                 mask = 0;
128
129                 for ( i = 0; indexes[i] != NULL; i++ ) {
130                         slap_mask_t index;
131                         rc = slap_str2index( indexes[i], &index );
132
133                         if( rc != LDAP_SUCCESS ) {
134                                 fprintf( stderr, "%s: line %d: "
135                                         "index type \"%s\" undefined\n",
136                                         fname, lineno, indexes[i] );
137                                 return LDAP_PARAM_ERROR;
138                         }
139
140                         mask |= index;
141                 }
142         }
143
144         if( !mask ) {
145                 fprintf( stderr, "%s: line %d: "
146                         "no indexes selected\n",
147                         fname, lineno );
148                 return LDAP_PARAM_ERROR;
149         }
150
151         for ( i = 0; attrs[i] != NULL; i++ ) {
152                 AttrInfo        *a;
153                 AttributeDescription *ad;
154                 const char *text;
155 #ifdef LDAP_COMP_MATCH
156                 ComponentReference* cr = NULL;
157                 AttrInfo *a_cr = NULL;
158 #endif
159
160                 if( strcasecmp( attrs[i], "default" ) == 0 ) {
161                         bdb->bi_defaultmask |= mask;
162                         continue;
163                 }
164
165 #ifdef LDAP_COMP_MATCH
166                 if ( is_component_reference( attrs[i] ) ) {
167                         rc = extract_component_reference( attrs[i], &cr );
168                         if ( rc != LDAP_SUCCESS ) {
169                                 fprintf( stderr, "%s: line %d: "
170                                         "index component reference\"%s\" undefined\n",
171                                         fname, lineno, attrs[i] );
172                                 return rc;
173                         }
174                         cr->cr_indexmask = mask;
175                         /*
176                          * After extracting a component reference
177                          * only the name of a attribute will be remaining
178                          */
179                 } else {
180                         cr = NULL;
181                 }
182 #endif
183                 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
184
185 #ifdef LDAP_COMP_MATCH
186                 a->ai_cr = NULL;
187 #endif
188                 ad = NULL;
189                 rc = slap_str2ad( attrs[i], &ad, &text );
190
191                 if( rc != LDAP_SUCCESS ) {
192                         fprintf( stderr, "%s: line %d: "
193                                 "index attribute \"%s\" undefined\n",
194                                 fname, lineno, attrs[i] );
195                         return rc;
196                 }
197
198                 if( slap_ad_is_binary( ad ) ) {
199                         fprintf( stderr, "%s: line %d: "
200                                 "index of attribute \"%s\" disallowed\n",
201                                 fname, lineno, attrs[i] );
202                         return LDAP_UNWILLING_TO_PERFORM;
203                 }
204
205                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
206                         ad->ad_type->sat_approx
207                                 && ad->ad_type->sat_approx->smr_indexer
208                                 && ad->ad_type->sat_approx->smr_filter ) )
209                 {
210                         fprintf( stderr, "%s: line %d: "
211                                 "approx index of attribute \"%s\" disallowed\n",
212                                 fname, lineno, attrs[i] );
213                         return LDAP_INAPPROPRIATE_MATCHING;
214                 }
215
216                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
217                         ad->ad_type->sat_equality
218                                 && ad->ad_type->sat_equality->smr_indexer
219                                 && ad->ad_type->sat_equality->smr_filter ) )
220                 {
221                         fprintf( stderr, "%s: line %d: "
222                                 "equality index of attribute \"%s\" disallowed\n",
223                                 fname, lineno, attrs[i] );
224                         return LDAP_INAPPROPRIATE_MATCHING;
225                 }
226
227                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
228                         ad->ad_type->sat_substr
229                                 && ad->ad_type->sat_substr->smr_indexer
230                                 && ad->ad_type->sat_substr->smr_filter ) )
231                 {
232                         fprintf( stderr, "%s: line %d: "
233                                 "substr index of attribute \"%s\" disallowed\n",
234                                 fname, lineno, attrs[i] );
235                         return LDAP_INAPPROPRIATE_MATCHING;
236                 }
237
238                 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
239                         ad->ad_cname.bv_val, mask, 0 ); 
240
241                 a->ai_desc = ad;
242
243                 if ( bdb->bi_flags & BDB_IS_OPEN ) {
244                         a->ai_indexmask = 0;
245                         a->ai_newmask = mask;
246                 } else {
247                         a->ai_indexmask = mask;
248                         a->ai_newmask = 0;
249                 }
250
251 #ifdef LDAP_COMP_MATCH
252                 if ( cr ) {
253                         a_cr = bdb_attr_mask( bdb, ad );
254                         if ( a_cr ) {
255                                 /*
256                                  * AttrInfo is already in AVL
257                                  * just add the extracted component reference
258                                  * in the AttrInfo
259                                  */
260                                 rc = insert_component_reference( cr, &a_cr->ai_cr );
261                                 if ( rc != LDAP_SUCCESS) {
262                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
263                                         return LDAP_PARAM_ERROR;
264                                 }
265                                 continue;
266                         } else {
267                                 rc = insert_component_reference( cr, &a->ai_cr );
268                                 if ( rc != LDAP_SUCCESS) {
269                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
270                                         return LDAP_PARAM_ERROR;
271                                 }
272                         }
273                 }
274 #endif
275                 rc = ainfo_insert( bdb, a );
276                 if( rc ) {
277                         if ( bdb->bi_flags & BDB_IS_OPEN ) {
278                                 AttrInfo *b = bdb_attr_mask( bdb, ad );
279                                 /* If we were editing this attr, reset it */
280                                 b->ai_indexmask &= ~BDB_INDEX_DELETING;
281                                 /* If this is leftover from a previous add, commit it */
282                                 if ( b->ai_newmask )
283                                         b->ai_indexmask = b->ai_newmask;
284                                 b->ai_newmask = a->ai_newmask;
285                                 ch_free( a );
286                                 continue;
287                         }
288                         fprintf( stderr, "%s: line %d: duplicate index definition "
289                                 "for attr \"%s\"" SLAPD_CONF_UNKNOWN_IGNORED ".\n",
290                                 fname, lineno, attrs[i] );
291
292                         return LDAP_PARAM_ERROR;
293                 }
294         }
295
296         ldap_charray_free( attrs );
297         if ( indexes != NULL ) ldap_charray_free( indexes );
298
299         return LDAP_SUCCESS;
300 }
301
302 static int
303 bdb_attr_index_unparser( void *v1, void *v2 )
304 {
305         AttrInfo *ai = v1;
306         BerVarray *bva = v2;
307         struct berval bv;
308         char *ptr;
309
310         slap_index2bvlen( ai->ai_indexmask, &bv );
311         if ( bv.bv_len ) {
312                 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
313                 ptr = ch_malloc( bv.bv_len+1 );
314                 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
315                 *bv.bv_val++ = ' ';
316                 slap_index2bv( ai->ai_indexmask, &bv );
317                 bv.bv_val = ptr;
318                 ber_bvarray_add( bva, &bv );
319         }
320         return 0;
321 }
322
323 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
324 static AttrInfo aidef = { &addef };
325
326 void
327 bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva )
328 {
329         int i;
330
331         if ( bdb->bi_defaultmask ) {
332                 aidef.ai_indexmask = bdb->bi_defaultmask;
333                 bdb_attr_index_unparser( &aidef, bva );
334         }
335         for ( i=0; i<bdb->bi_nattrs; i++ )
336                 bdb_attr_index_unparser( bdb->bi_attrs[i], bva );
337 }
338
339 void
340 bdb_attr_info_free( AttrInfo *ai )
341 {
342 #ifdef LDAP_COMP_MATCH
343         free( ai->ai_cr );
344 #endif
345         free( ai );
346 }
347
348 void
349 bdb_attr_index_destroy( struct bdb_info *bdb )
350 {
351         int i;
352
353         for ( i=0; i<bdb->bi_nattrs; i++ ) 
354                 bdb_attr_info_free( bdb->bi_attrs[i] );
355
356         free( bdb->bi_attrs );
357 }
358
359 void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
360 {
361         int i;
362
363         i = bdb_attr_slot( bdb, ad, NULL );
364         if ( i >= 0 ) {
365                 bdb_attr_info_free( bdb->bi_attrs[i] );
366                 bdb->bi_nattrs--;
367                 for (; i<bdb->bi_nattrs; i++)
368                         bdb->bi_attrs[i] = bdb->bi_attrs[i+1];
369         }
370 }
371
372 void bdb_attr_flush( struct bdb_info *bdb )
373 {
374         int i;
375
376         for ( i=0; i<bdb->bi_nattrs; i++ ) {
377                 if ( bdb->bi_attrs[i]->ai_indexmask & BDB_INDEX_DELETING ) {
378                         int j;
379                         bdb_attr_info_free( bdb->bi_attrs[i] );
380                         bdb->bi_nattrs--;
381                         for (j=i; j<bdb->bi_nattrs; j++)
382                                 bdb->bi_attrs[j] = bdb->bi_attrs[j+1];
383                         i--;
384                 }
385         }
386 }