return rc;
}
+static void
+sorted_attr_cmp( Operation *op, Attribute *old, Attribute *new,
+ Modifications ***mret, Modifications ***mcur )
+{
+ Modifications *mod, **modtail = *mret;
+ struct berval **adds, **nadds = NULL, **dels, **ndels = NULL;
+ const char *text;
+ unsigned int i = 0, j = 0, n = 0, o = 0, nn = new->a_numvals,
+ no = old->a_numvals;
+ int match = -1, rc;
+
+ assert( no != 0 );
+ assert( nn != 0 );
+
+ adds = op->o_tmpalloc( sizeof(struct berval *) * nn, op->o_tmpmemctx );
+ dels = op->o_tmpalloc( sizeof(struct berval *) * no, op->o_tmpmemctx );
+
+ if ( old->a_vals != old->a_nvals ) {
+ nadds = op->o_tmpalloc( sizeof(struct berval *) * nn, op->o_tmpmemctx );
+ ndels = op->o_tmpalloc( sizeof(struct berval *) * no, op->o_tmpmemctx );
+ }
+
+ do {
+ if ( n == nn ) {
+ if ( ndels ) {
+ ndels[i] = &old->a_vals[o];
+ }
+ dels[i++] = &old->a_vals[o++];
+ } else if ( o == no ) {
+ if ( nadds ) {
+ nadds[j] = &new->a_vals[n];
+ }
+ adds[j++] = &new->a_vals[n++];
+ } else {
+ rc = value_match( &match, old->a_desc,
+ old->a_desc->ad_type->sat_equality, SLAP_MR_EQUALITY,
+ &old->a_nvals[o], &new->a_nvals[n], &text );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "attr_cmp: "
+ "sorted vals attribute %s values can't be compared? (%s)\n",
+ old->a_desc->ad_cname.bv_val, text );
+ assert(0);
+ }
+ if ( match == 0 ) {
+ /* Value still present */
+ o++;
+ n++;
+ } else if ( match < 0 ) {
+ /* Old value not present anymore */
+ if ( ndels ) {
+ ndels[i] = &old->a_nvals[o];
+ }
+ dels[i++] = &old->a_vals[o++];
+ } else {
+ if ( nadds ) {
+ nadds[j] = &new->a_nvals[n];
+ }
+ adds[j++] = &new->a_vals[n++];
+ }
+ }
+ } while ( n < nn || o < no );
+
+ mod = **mcur;
+ if ( mod && i == no ) {
+ **mcur = mod->sml_next;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ /* If we deleted all, just use the replace */
+ if ( i && i != no ) {
+ mod = ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = LDAP_MOD_DELETE;
+ mod->sml_flags = 0;
+ mod->sml_desc = old->a_desc;
+ mod->sml_type = mod->sml_desc->ad_cname;
+ mod->sml_numvals = i;
+
+ mod->sml_values = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
+ if ( old->a_vals != old->a_nvals ) {
+ mod->sml_nvalues = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
+ } else {
+ mod->sml_nvalues = NULL;
+ }
+
+ for ( i=0; i < mod->sml_numvals; i++ ) {
+ ber_dupbv( &mod->sml_values[i], dels[i] );
+ if ( mod->sml_nvalues ) {
+ ber_dupbv( &mod->sml_nvalues[i], ndels[i] );
+ }
+ }
+
+ BER_BVZERO( &mod->sml_values[i] );
+ if ( mod->sml_nvalues ) {
+ BER_BVZERO( &mod->sml_nvalues[i] );
+ }
+
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ if ( j ) {
+ mod = ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = LDAP_MOD_ADD;
+ mod->sml_flags = 0;
+ mod->sml_desc = old->a_desc;
+ mod->sml_type = mod->sml_desc->ad_cname;
+ mod->sml_numvals = j;
+
+ mod->sml_values = ch_malloc( ( j + 1 ) * sizeof(struct berval) );
+ if ( old->a_vals != old->a_nvals ) {
+ mod->sml_nvalues = ch_malloc( ( j + 1 ) * sizeof(struct berval) );
+ } else {
+ mod->sml_nvalues = NULL;
+ }
+
+ for ( j=0; j < mod->sml_numvals; j++ ) {
+ ber_dupbv( &mod->sml_values[j], adds[j] );
+ if ( mod->sml_nvalues ) {
+ ber_dupbv( &mod->sml_nvalues[j], nadds[j] );
+ }
+ }
+
+ BER_BVZERO( &mod->sml_values[j] );
+ if ( mod->sml_nvalues ) {
+ BER_BVZERO( &mod->sml_nvalues[j] );
+ }
+
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+
+ if ( old->a_vals != old->a_nvals ) {
+ op->o_tmpfree( ndels, op->o_tmpmemctx );
+ op->o_tmpfree( nadds, op->o_tmpmemctx );
+ }
+ op->o_tmpfree( dels, op->o_tmpmemctx );
+ op->o_tmpfree( adds, op->o_tmpmemctx );
+
+ /* advance to next element */
+ mod = **mcur;
+ if ( mod ) {
+ *mcur = &mod->sml_next;
+ }
+ *mret = modtail;
+}
+
/* Compare the attribute from the old entry to the one in the new
* entry. The Modifications from the new entry will either be left
* in place, or changed to an Add or Delete as needed.
* if we know there are other valid mods.
*/
if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
- old->a_desc == slap_schema.si_ad_modifyTimestamp ))
+ old->a_desc == slap_schema.si_ad_modifyTimestamp )) {
attr_cmp( op, NULL, new, &modtail, &ml );
- else
+ } else if ( old->a_flags & SLAP_ATTR_SORTED_VALS ) {
+ sorted_attr_cmp( op, old, new, &modtail, &ml );
+ } else {
attr_cmp( op, old, new, &modtail, &ml );
+ }
+
new = new->a_next;
old = old->a_next;
}