const char **text,
char *textbuf, size_t textlen )
{
- int i, j, rc = LDAP_SUCCESS;
+ int i, j, numvals = 0, nummods,
+ rc = LDAP_SUCCESS;
BerVarray nvals = NULL, nmods;
/*
* - count the new values
*
* - if the existing values are less than the new ones {
- * // current code
- * - normalize the existing values
+ * - normalize all the existing values
* - for each new value {
* - normalize
* - check with existing
* - cross-check with already normalized new vals
* }
* } else {
- * // to be implemented
* - for each new value {
* - normalize
* - cross-check with already normalized new vals
* performances should not change; they will in case of error.
*/
+ for ( nummods = 0; mods[ nummods ].bv_val != NULL; nummods++ )
+ /* count new values */ ;
+
if ( vals ) {
- for ( j = 0; vals[ j ].bv_val != NULL; j++ )
+ for ( numvals = 0; vals[ numvals ].bv_val != NULL; numvals++ )
/* count existing values */ ;
+ }
- nvals = ch_calloc( j + 1, sizeof( struct berval ) );
+ if ( numvals > 0 && numvals < nummods ) {
+ nvals = ch_calloc( numvals + 1, sizeof( struct berval ) );
/* normalize the existing values first */
for ( j = 0; vals[ j ].bv_val != NULL; j++ ) {
nvals[ j ].bv_val = NULL;
}
- for ( i = 0; mods[ i ].bv_val != NULL; i++ )
- /* count new values */ ;
-
- nmods = ch_calloc( i + 1, sizeof( struct berval ) );
+ /*
+ * If the existing values are less than the new values,
+ * it is more convenient to normalize all the existing
+ * values and test each new value against them first,
+ * then to other already normalized values
+ */
+ nmods = ch_calloc( nummods + 1, sizeof( struct berval ) );
for ( i = 0; mods[ i ].bv_val != NULL; i++ ) {
-
rc = value_normalize( ad, SLAP_MR_EQUALITY,
&mods[ i ], &nmods[ i ], text );
goto return_results;
}
- if ( vals ) {
+ if ( numvals > 0 && numvals < nummods ) {
for ( j = 0; nvals[ j ].bv_val; j++ ) {
#ifdef QUICK_DIRTY_DUPLICATE_CHECK
if ( bvmatch( &nmods[ i ], &nvals[ j ] ) ) {
}
}
}
-
+
for ( j = 0; j < i; j++ ) {
#ifdef QUICK_DIRTY_DUPLICATE_CHECK
if ( bvmatch( &nmods[ i ], &nmods[ j ] ) ) {
}
nmods[ i ].bv_val = NULL;
+ /*
+ * if new values are more than existing values, it is more
+ * convenient to normalize and check all new values first,
+ * then check each new value against existing values, which
+ * can be normalized in place
+ */
+
+ if ( numvals >= nummods ) {
+ for ( j = 0; vals[ j ].bv_val; j++ ) {
+ struct berval asserted;
+
+ rc = value_normalize( ad, SLAP_MR_EQUALITY,
+ &vals[ j ], &asserted, text );
+
+ if ( rc != LDAP_SUCCESS ) {
+ goto return_results;
+ }
+
+ for ( i = 0; nmods[ i ].bv_val; i++ ) {
+#ifdef QUICK_DIRTY_DUPLICATE_CHECK
+ if ( bvmatch( &nmods[ i ], &asserted ) ) {
+#else /* !QUICK_DIRTY_DUPLICATE_CHECK */
+ int match;
+
+ rc = (mr->smr_match)( &match,
+ SLAP_MR_VALUE_SYNTAX_MATCH,
+ ad->ad_type->sat_syntax,
+ mr, &nmods[ i ], &asserted );
+ if ( rc != LDAP_SUCCESS ) {
+ goto return_results;
+ }
+
+ if ( match == 0 ) {
+#endif /* !QUICK_DIRTY_DUPLICATE_CHECK */
+ snprintf( textbuf, textlen,
+ "%s: value #%d provided more than once",
+ ad->ad_cname.bv_val, j );
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ goto return_results;
+ }
+ }
+
+ }
+ }
+
return_results:;
if ( nvals ) {
ber_bvarray_free( nvals );
return LDAP_NO_SUCH_ATTRIBUTE;
}
- /* find each value to delete */
+ /* find each value to delete
+ *
+ * FIXME: need to optimize this operation too,
+ * see modify_check_duplicates()
+ */
for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) {
int rc;
struct berval asserted;