2 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * Copyright (c) 1995 Regents of the University of Michigan.
9 * Redistribution and use in source and binary forms are permitted
10 * provided that this notice is preserved and that due credit is given
11 * to the University of Michigan at Ann Arbor. The name of the University
12 * may not be used to endorse or promote products derived from this
13 * software without specific prior written permission. This software
14 * is provided ``as is'' without express or implied warranty.
22 modify_check_duplicates(
23 AttributeDescription *ad,
28 char *textbuf, size_t textlen )
30 int i, j, numvals = 0, nummods,
32 BerVarray nvals = NULL, nmods;
35 * FIXME: better do the following
37 * - count the existing values
38 * - count the new values
40 * - if the existing values are less than the new ones {
41 * - normalize all the existing values
42 * - for each new value {
44 * - check with existing
45 * - cross-check with already normalized new vals
48 * - for each new value {
50 * - cross-check with already normalized new vals
52 * - for each existing value {
54 * - check with already normalized new values
58 * The first case is good when adding a lot of new values,
59 * and significantly at first import of values (e.g. adding
60 * a new group); the latter case seems to be quite important
61 * as well, because it is likely to be the most frequently
62 * used when administering the entry. The current
63 * implementation will always normalize all the existing
64 * values before checking. If there's no duplicate, the
65 * performances should not change; they will in case of error.
68 for ( nummods = 0; mods[ nummods ].bv_val != NULL; nummods++ )
69 /* count new values */ ;
72 for ( numvals = 0; vals[ numvals ].bv_val != NULL; numvals++ )
73 /* count existing values */ ;
75 if ( numvals < nummods ) {
76 nvals = ch_calloc( numvals + 1, sizeof( struct berval ) );
78 /* normalize the existing values first */
79 for ( j = 0; vals[ j ].bv_val != NULL; j++ ) {
80 rc = value_normalize( ad, SLAP_MR_EQUALITY,
81 &vals[ j ], &nvals[ j ], text );
83 /* existing attribute values must normalize */
84 assert( rc == LDAP_SUCCESS );
86 if ( rc != LDAP_SUCCESS ) {
87 nvals[ j ].bv_val = NULL;
91 nvals[ j ].bv_val = NULL;
96 * If the existing values are less than the new values,
97 * it is more convenient to normalize all the existing
98 * values and test each new value against them first,
99 * then to other already normalized values
101 nmods = ch_calloc( nummods + 1, sizeof( struct berval ) );
103 for ( i = 0; mods[ i ].bv_val != NULL; i++ ) {
104 rc = value_normalize( ad, SLAP_MR_EQUALITY,
105 &mods[ i ], &nmods[ i ], text );
107 if ( rc != LDAP_SUCCESS ) {
108 nmods[ i ].bv_val = NULL;
112 if ( numvals > 0 && numvals < nummods ) {
113 for ( j = 0; nvals[ j ].bv_val; j++ ) {
116 rc = (*mr->smr_match)( &match,
117 SLAP_MR_VALUE_SYNTAX_MATCH,
118 ad->ad_type->sat_syntax,
119 mr, &nmods[ i ], &nvals[ j ] );
120 if ( rc != LDAP_SUCCESS ) {
121 nmods[ i + 1 ].bv_val = NULL;
123 snprintf( textbuf, textlen,
124 "%s: matching rule failed",
125 ad->ad_cname.bv_val );
131 snprintf( textbuf, textlen,
132 "%s: value #%d provided more than once",
133 ad->ad_cname.bv_val, i );
134 rc = LDAP_TYPE_OR_VALUE_EXISTS;
135 nmods[ i + 1 ].bv_val = NULL;
141 for ( j = 0; j < i; j++ ) {
144 rc = (*mr->smr_match)( &match,
145 SLAP_MR_VALUE_SYNTAX_MATCH,
146 ad->ad_type->sat_syntax,
147 mr, &nmods[ i ], &nmods[ j ] );
148 if ( rc != LDAP_SUCCESS ) {
149 nmods[ i + 1 ].bv_val = NULL;
151 snprintf( textbuf, textlen,
152 "%s: matching rule failed",
153 ad->ad_cname.bv_val );
159 snprintf( textbuf, textlen,
160 "%s: value #%d provided more than once",
161 ad->ad_cname.bv_val, j );
162 rc = LDAP_TYPE_OR_VALUE_EXISTS;
163 nmods[ i + 1 ].bv_val = NULL;
168 nmods[ i ].bv_val = NULL;
171 * if new values are more than existing values, it is more
172 * convenient to normalize and check all new values first,
173 * then check each new value against existing values, which
174 * can be normalized in place
177 if ( numvals >= nummods ) {
178 for ( j = 0; vals[ j ].bv_val; j++ ) {
179 struct berval asserted;
181 rc = value_normalize( ad, SLAP_MR_EQUALITY,
182 &vals[ j ], &asserted, text );
184 if ( rc != LDAP_SUCCESS ) {
188 for ( i = 0; nmods[ i ].bv_val; i++ ) {
191 rc = (*mr->smr_match)( &match,
192 SLAP_MR_VALUE_SYNTAX_MATCH,
193 ad->ad_type->sat_syntax,
194 mr, &nmods[ i ], &asserted );
195 if ( rc != LDAP_SUCCESS ) {
197 snprintf( textbuf, textlen,
198 "%s: matching rule failed",
199 ad->ad_cname.bv_val );
205 snprintf( textbuf, textlen,
206 "%s: value #%d provided more than once",
207 ad->ad_cname.bv_val, j );
208 rc = LDAP_TYPE_OR_VALUE_EXISTS;
218 ber_bvarray_free( nvals );
221 ber_bvarray_free( nmods );
232 char *textbuf, size_t textlen
237 MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
240 switch( mod->sm_op ) {
244 case LDAP_MOD_REPLACE:
252 a = attr_find( e->e_attrs, mod->sm_desc );
254 /* check if the values we're adding already exist */
255 if( mr == NULL || !mr->smr_match ) {
257 /* do not allow add of additional attribute
258 if no equality rule exists */
260 snprintf( textbuf, textlen,
261 "modify/%s: %s: no equality matching rule",
262 op, mod->sm_desc->ad_cname.bv_val );
263 return LDAP_INAPPROPRIATE_MATCHING;
266 for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) {
267 /* test asserted values against existing values */
269 for( j = 0; a->a_vals[j].bv_val != NULL; j++ ) {
270 if ( bvmatch( &mod->sm_bvalues[i],
273 /* value exists already */
275 snprintf( textbuf, textlen,
276 "modify/%s: %s: value #%i already exists",
277 op, mod->sm_desc->ad_cname.bv_val, j );
278 return LDAP_TYPE_OR_VALUE_EXISTS;
283 /* test asserted values against themselves */
284 for( j = 0; j < i; j++ ) {
285 if ( bvmatch( &mod->sm_bvalues[i],
286 &mod->sm_bvalues[j] ) ) {
288 /* value exists already */
290 snprintf( textbuf, textlen,
291 "modify/%s: %s: value #%i already exists",
292 op, mod->sm_desc->ad_cname.bv_val, j );
293 return LDAP_TYPE_OR_VALUE_EXISTS;
300 * The original code performs ( n ) normalizations
301 * and ( n * ( n - 1 ) / 2 ) matches, which hide
302 * the same number of normalizations. The new code
303 * performs the same number of normalizations ( n )
304 * and ( n * ( n - 1 ) / 2 ) mem compares, far less
305 * expensive than an entire match, if a match is
306 * equivalent to a normalization and a mem compare ...
308 * This is far more memory expensive than the previous,
309 * but it can heavily improve performances when big
310 * chunks of data are added (typical example is a group
311 * with thousands of DN-syntax members; on my system:
312 * for members of 5-RDN DNs,
314 members orig bvmatch (dirty) new
315 1000 0m38.456s 0m0.553s 0m0.608s
316 2000 2m33.341s 0m0.851s 0m1.003s
318 * Moreover, 100 groups with 10000 members each were
319 * added in 37m27.933s (an analogous LDIF file was
320 * loaded into Active Directory in 38m28.682s, BTW).
322 * Maybe we could switch to the new algorithm when
323 * the number of values overcomes a given threshold?
328 if ( mod->sm_bvalues[ 1 ].bv_val == 0 ) {
330 struct berval asserted;
333 rc = value_normalize( mod->sm_desc, SLAP_MR_EQUALITY,
334 &mod->sm_bvalues[ 0 ], &asserted, text );
336 if ( rc != LDAP_SUCCESS ) {
340 for ( i = 0; a->a_vals[ i ].bv_val; i++ ) {
343 rc = value_match( &match, mod->sm_desc, mr,
344 SLAP_MR_VALUE_SYNTAX_MATCH,
345 &a->a_vals[ i ], &asserted, text );
347 if( rc == LDAP_SUCCESS && match == 0 ) {
348 free( asserted.bv_val );
350 snprintf( textbuf, textlen,
351 "modify/%s: %s: value #0 already exists",
352 op, mod->sm_desc->ad_cname.bv_val, 0 );
353 return LDAP_TYPE_OR_VALUE_EXISTS;
359 rc = modify_check_duplicates( mod->sm_desc, mr,
360 a ? a->a_vals : NULL, mod->sm_bvalues,
361 text, textbuf, textlen );
363 if ( rc != LDAP_SUCCESS ) {
370 if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) {
371 /* this should return result of attr_merge */
373 snprintf( textbuf, textlen,
374 "modify/%s: %s: merge error",
375 op, mod->sm_desc->ad_cname.bv_val );
383 modify_delete_values(
387 char *textbuf, size_t textlen
390 int i, j, k, rc = LDAP_SUCCESS;
392 MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
393 BerVarray nvals = NULL;
396 /* delete the entire attribute */
397 if ( mod->sm_bvalues == NULL ) {
398 rc = attr_delete( &e->e_attrs, mod->sm_desc );
400 if( rc != LDAP_SUCCESS ) {
402 snprintf( textbuf, textlen,
403 "modify/delete: %s: no such attribute",
404 mod->sm_desc->ad_cname.bv_val );
405 rc = LDAP_NO_SUCH_ATTRIBUTE;
410 if( mr == NULL || !mr->smr_match ) {
411 /* disallow specific attributes from being deleted if
414 snprintf( textbuf, textlen,
415 "modify/delete: %s: no equality matching rule",
416 mod->sm_desc->ad_cname.bv_val );
417 return LDAP_INAPPROPRIATE_MATCHING;
420 /* delete specific values - find the attribute first */
421 if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
423 snprintf( textbuf, textlen,
424 "modify/delete: %s: no such attribute",
425 mod->sm_desc->ad_cname.bv_val );
426 return LDAP_NO_SUCH_ATTRIBUTE;
429 /* find each value to delete */
430 for ( j = 0; a->a_vals[ j ].bv_val != NULL; j++ )
431 /* count existing values */ ;
433 nvals = (BerVarray)ch_calloc( j + 1, sizeof ( struct berval ) );
435 /* normalize existing values */
436 for ( j = 0; a->a_vals[ j ].bv_val != NULL; j++ ) {
437 rc = value_normalize( a->a_desc, SLAP_MR_EQUALITY,
438 &a->a_vals[ j ], &nvals[ j ], text );
440 if ( rc != LDAP_SUCCESS ) {
441 nvals[ j ].bv_val = NULL;
446 for ( i = 0; mod->sm_bvalues[ i ].bv_val != NULL; i++ ) {
447 struct berval asserted;
450 /* normalize the value to be deleted */
451 rc = value_normalize( mod->sm_desc, SLAP_MR_EQUALITY,
452 &mod->sm_bvalues[ i ], &asserted, text );
454 if( rc != LDAP_SUCCESS ) {
459 for ( j = 0; nvals[ j ].bv_val != NULL; j++ ) {
462 if ( nvals[ j ].bv_val == &dummy ) {
466 rc = (*mr->smr_match)( &match,
467 SLAP_MR_VALUE_SYNTAX_MATCH,
468 a->a_desc->ad_type->sat_syntax,
469 mr, &nvals[ j ], &asserted );
471 if ( rc != LDAP_SUCCESS ) {
472 free( asserted.bv_val );
474 snprintf( textbuf, textlen,
475 "%s: matching rule failed",
476 mod->sm_desc->ad_cname.bv_val );
486 /* delete value and mark it as dummy */
487 free( nvals[ j ].bv_val );
488 nvals[ j ].bv_val = &dummy;
493 free( asserted.bv_val );
497 snprintf( textbuf, textlen,
498 "modify/delete: %s: no such value",
499 mod->sm_desc->ad_cname.bv_val );
500 rc = LDAP_NO_SUCH_ATTRIBUTE;
505 /* compact array skipping dummies */
506 for ( k = 0, j = 0; nvals[ k ].bv_val != NULL; j++, k++ ) {
508 /* delete and skip dummies */ ;
509 for ( ; nvals[ k ].bv_val == &dummy; k++ ) {
510 free( a->a_vals[ k ].bv_val );
514 a->a_vals[ j ] = a->a_vals[ k ];
517 if ( a->a_vals[ k ].bv_val == NULL ) {
521 a->a_vals[ j ].bv_val = NULL;
523 assert( i == k - j );
525 /* if no values remain, delete the entire attribute */
526 if ( a->a_vals[0].bv_val == NULL ) {
527 if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
529 snprintf( textbuf, textlen,
530 "modify/delete: %s: no such attribute",
531 mod->sm_desc->ad_cname.bv_val );
532 rc = LDAP_NO_SUCH_ATTRIBUTE;
538 /* delete the remaining normalized values */
539 for ( j = 0; nvals[ j ].bv_val != NULL; j++ ) {
540 if ( nvals[ j ].bv_val != &dummy ) {
541 ber_memfree( nvals[ j ].bv_val );
544 ber_memfree( nvals );
551 modify_replace_values(
555 char *textbuf, size_t textlen
558 (void) attr_delete( &e->e_attrs, mod->sm_desc );
560 if ( mod->sm_bvalues ) {
561 return modify_add_values( e, mod, text, textbuf, textlen );
574 if ( mod->sm_type.bv_val)
575 free( mod->sm_type.bv_val );
577 if ( mod->sm_bvalues != NULL )
578 ber_bvarray_free( mod->sm_bvalues );
591 for ( ; ml != NULL; ml = next ) {
594 slap_mod_free( &ml->sml_mod, 0 );