]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/attr.c
Allow updating (ADD/DEL within a single modify operation) the index
[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 = 0;
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                         rc = LDAP_PARAM_ERROR;
120                         goto done;
121                 }
122         }
123
124         if( indexes == NULL ) {
125                 mask = bdb->bi_defaultmask;
126
127         } else {
128                 mask = 0;
129
130                 for ( i = 0; indexes[i] != NULL; i++ ) {
131                         slap_mask_t index;
132                         rc = slap_str2index( indexes[i], &index );
133
134                         if( rc != LDAP_SUCCESS ) {
135                                 fprintf( stderr, "%s: line %d: "
136                                         "index type \"%s\" undefined\n",
137                                         fname, lineno, indexes[i] );
138                                 rc = LDAP_PARAM_ERROR;
139                                 goto done;
140                         }
141
142                         mask |= index;
143                 }
144         }
145
146         if( !mask ) {
147                 fprintf( stderr, "%s: line %d: "
148                         "no indexes selected\n",
149                         fname, lineno );
150                 rc = LDAP_PARAM_ERROR;
151                 goto done;
152         }
153
154         for ( i = 0; attrs[i] != NULL; i++ ) {
155                 AttrInfo        *a;
156                 AttributeDescription *ad;
157                 const char *text;
158 #ifdef LDAP_COMP_MATCH
159                 ComponentReference* cr = NULL;
160                 AttrInfo *a_cr = NULL;
161 #endif
162
163                 if( strcasecmp( attrs[i], "default" ) == 0 ) {
164                         bdb->bi_defaultmask |= mask;
165                         continue;
166                 }
167
168 #ifdef LDAP_COMP_MATCH
169                 if ( is_component_reference( attrs[i] ) ) {
170                         rc = extract_component_reference( attrs[i], &cr );
171                         if ( rc != LDAP_SUCCESS ) {
172                                 fprintf( stderr, "%s: line %d: "
173                                         "index component reference\"%s\" undefined\n",
174                                         fname, lineno, attrs[i] );
175                                 goto done;
176                         }
177                         cr->cr_indexmask = mask;
178                         /*
179                          * After extracting a component reference
180                          * only the name of a attribute will be remaining
181                          */
182                 } else {
183                         cr = NULL;
184                 }
185 #endif
186                 ad = NULL;
187                 rc = slap_str2ad( attrs[i], &ad, &text );
188
189                 if( rc != LDAP_SUCCESS ) {
190                         fprintf( stderr, "%s: line %d: "
191                                 "index attribute \"%s\" undefined\n",
192                                 fname, lineno, attrs[i] );
193                         goto done;
194                 }
195
196                 if( slap_ad_is_binary( ad ) ) {
197                         fprintf( stderr, "%s: line %d: "
198                                 "index of attribute \"%s\" disallowed\n",
199                                 fname, lineno, attrs[i] );
200                         rc = LDAP_UNWILLING_TO_PERFORM;
201                         goto done;
202                 }
203
204                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
205                         ad->ad_type->sat_approx
206                                 && ad->ad_type->sat_approx->smr_indexer
207                                 && ad->ad_type->sat_approx->smr_filter ) )
208                 {
209                         fprintf( stderr, "%s: line %d: "
210                                 "approx index of attribute \"%s\" disallowed\n",
211                                 fname, lineno, attrs[i] );
212                         rc = LDAP_INAPPROPRIATE_MATCHING;
213                         goto done;
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                         rc = LDAP_INAPPROPRIATE_MATCHING;
225                         goto done;
226                 }
227
228                 if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
229                         ad->ad_type->sat_substr
230                                 && ad->ad_type->sat_substr->smr_indexer
231                                 && ad->ad_type->sat_substr->smr_filter ) )
232                 {
233                         fprintf( stderr, "%s: line %d: "
234                                 "substr index of attribute \"%s\" disallowed\n",
235                                 fname, lineno, attrs[i] );
236                         rc = LDAP_INAPPROPRIATE_MATCHING;
237                         goto done;
238                 }
239
240                 Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
241                         ad->ad_cname.bv_val, mask, 0 ); 
242
243                 a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
244
245 #ifdef LDAP_COMP_MATCH
246                 a->ai_cr = NULL;
247 #endif
248                 a->ai_desc = ad;
249
250                 if ( bdb->bi_flags & BDB_IS_OPEN ) {
251                         a->ai_indexmask = 0;
252                         a->ai_newmask = mask;
253                 } else {
254                         a->ai_indexmask = mask;
255                         a->ai_newmask = 0;
256                 }
257
258 #ifdef LDAP_COMP_MATCH
259                 if ( cr ) {
260                         a_cr = bdb_attr_mask( bdb, ad );
261                         if ( a_cr ) {
262                                 /*
263                                  * AttrInfo is already in AVL
264                                  * just add the extracted component reference
265                                  * in the AttrInfo
266                                  */
267                                 rc = insert_component_reference( cr, &a_cr->ai_cr );
268                                 if ( rc != LDAP_SUCCESS) {
269                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
270                                         rc = LDAP_PARAM_ERROR;
271                                         goto done;
272                                 }
273                                 continue;
274                         } else {
275                                 rc = insert_component_reference( cr, &a->ai_cr );
276                                 if ( rc != LDAP_SUCCESS) {
277                                         fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
278                                         rc = LDAP_PARAM_ERROR;
279                                         goto done;
280                                 }
281                         }
282                 }
283 #endif
284                 rc = ainfo_insert( bdb, a );
285                 if( rc ) {
286                         if ( bdb->bi_flags & BDB_IS_OPEN ) {
287                                 AttrInfo *b = bdb_attr_mask( bdb, ad );
288                                 /* If we were editing this attr, reset it */
289                                 b->ai_indexmask &= ~BDB_INDEX_DELETING;
290                                 /* If this is leftover from a previous add, commit it */
291                                 if ( b->ai_newmask )
292                                         b->ai_indexmask = b->ai_newmask;
293                                 b->ai_newmask = a->ai_newmask;
294                                 ch_free( a );
295                                 rc = 0;
296                                 continue;
297                         }
298                         fprintf( stderr,
299                                 "%s: line %d: duplicate index definition for attr \"%s\".\n",
300                                 fname, lineno, attrs[i] );
301
302                         rc = LDAP_PARAM_ERROR;
303                         goto done;
304                 }
305         }
306
307 done:
308         ldap_charray_free( attrs );
309         if ( indexes != NULL ) ldap_charray_free( indexes );
310
311         return rc;
312 }
313
314 static int
315 bdb_attr_index_unparser( void *v1, void *v2 )
316 {
317         AttrInfo *ai = v1;
318         BerVarray *bva = v2;
319         struct berval bv;
320         char *ptr;
321
322         slap_index2bvlen( ai->ai_indexmask, &bv );
323         if ( bv.bv_len ) {
324                 bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
325                 ptr = ch_malloc( bv.bv_len+1 );
326                 bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
327                 *bv.bv_val++ = ' ';
328                 slap_index2bv( ai->ai_indexmask, &bv );
329                 bv.bv_val = ptr;
330                 ber_bvarray_add( bva, &bv );
331         }
332         return 0;
333 }
334
335 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
336 static AttrInfo aidef = { &addef };
337
338 void
339 bdb_attr_index_unparse( struct bdb_info *bdb, BerVarray *bva )
340 {
341         int i;
342
343         if ( bdb->bi_defaultmask ) {
344                 aidef.ai_indexmask = bdb->bi_defaultmask;
345                 bdb_attr_index_unparser( &aidef, bva );
346         }
347         for ( i=0; i<bdb->bi_nattrs; i++ )
348                 bdb_attr_index_unparser( bdb->bi_attrs[i], bva );
349 }
350
351 void
352 bdb_attr_info_free( AttrInfo *ai )
353 {
354 #ifdef LDAP_COMP_MATCH
355         free( ai->ai_cr );
356 #endif
357         free( ai );
358 }
359
360 void
361 bdb_attr_index_destroy( struct bdb_info *bdb )
362 {
363         int i;
364
365         for ( i=0; i<bdb->bi_nattrs; i++ ) 
366                 bdb_attr_info_free( bdb->bi_attrs[i] );
367
368         free( bdb->bi_attrs );
369 }
370
371 void bdb_attr_index_free( struct bdb_info *bdb, AttributeDescription *ad )
372 {
373         int i;
374
375         i = bdb_attr_slot( bdb, ad, NULL );
376         if ( i >= 0 ) {
377                 bdb_attr_info_free( bdb->bi_attrs[i] );
378                 bdb->bi_nattrs--;
379                 for (; i<bdb->bi_nattrs; i++)
380                         bdb->bi_attrs[i] = bdb->bi_attrs[i+1];
381         }
382 }
383
384 void bdb_attr_flush( struct bdb_info *bdb )
385 {
386         int i;
387
388         for ( i=0; i<bdb->bi_nattrs; i++ ) {
389                 if ( bdb->bi_attrs[i]->ai_indexmask & BDB_INDEX_DELETING ) {
390                         int j;
391                         bdb_attr_info_free( bdb->bi_attrs[i] );
392                         bdb->bi_nattrs--;
393                         for (j=i; j<bdb->bi_nattrs; j++)
394                                 bdb->bi_attrs[j] = bdb->bi_attrs[j+1];
395                         i--;
396                 }
397         }
398 }