]> git.sur5r.net Git - openldap/commitdiff
Preliminary sorted value support
authorHoward Chu <hyc@openldap.org>
Mon, 24 Sep 2007 01:31:23 +0000 (01:31 +0000)
committerHoward Chu <hyc@openldap.org>
Mon, 24 Sep 2007 01:31:23 +0000 (01:31 +0000)
14 files changed:
servers/slapd/add.c
servers/slapd/attr.c
servers/slapd/back-bdb/monitor.c
servers/slapd/bconfig.c
servers/slapd/entry.c
servers/slapd/modify.c
servers/slapd/mods.c
servers/slapd/overlays/dynlist.c
servers/slapd/overlays/memberof.c
servers/slapd/overlays/syncprov.c
servers/slapd/proto-slap.h
servers/slapd/slap.h
servers/slapd/slapi/slapi_utils.c
servers/slapd/syncrepl.c

index 1525b4e3e246983215b9250b497c43b6f55c24df..9c6ca2e6eedd06e66cc47378a482eeab49e54188 100644 (file)
@@ -490,6 +490,9 @@ slap_mods2entry(
                } else {
                        attr->a_nvals = attr->a_vals;
                }
+               /* slap_mods_check() gives us sorted results */
+               if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
+                       attr->a_flags |= SLAP_ATTR_SORTED_VALS;
 
                *tail = attr;
                tail = &attr->a_next;
index f4d76dc21c92269ea15419251e557bb8d2ace93a..7112358c1e5b25f6aef363b8aaa9a2a768c0b449 100644 (file)
@@ -281,6 +281,74 @@ attrs_dup( Attribute *a )
        return anew;
 }
 
+int
+attr_valfind(
+       Attribute *a,
+       unsigned flags,
+       struct berval *val,
+       unsigned *slot,
+       void *ctx )
+{
+       struct berval nval = BER_BVNULL, *cval;
+       MatchingRule *mr = a->a_desc->ad_type->sat_equality;
+       const char *text;
+       int match = -1, rc;
+       unsigned i;
+
+       if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) &&
+               mr->smr_normalize )
+       {
+               rc = (mr->smr_normalize)(
+                       flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX),
+                       a->a_desc->ad_type->sat_syntax,
+                       mr, val, &nval, ctx );
+
+               if( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+               cval = &nval;
+       } else {
+               cval = val;
+       }
+
+       if ( a->a_flags & SLAP_ATTR_SORTED_VALS ) {
+       /* Binary search */
+               unsigned base = 0, n = a->a_numvals;
+               int val = 0;
+
+               while ( 0 < n ) {
+                       unsigned pivot = n >> 1;
+                       i = base + pivot;
+                       rc = value_match( &match, a->a_desc, mr, flags,
+                               &a->a_nvals[i], cval, &text );
+                       if ( rc == LDAP_SUCCESS && match == 0 )
+                               break;
+                       n = pivot;
+                       if ( match > 0 )
+                               base = i+1;
+               }
+               if ( match > 0 )
+                       i++;
+       } else {
+       /* Linear search */
+               for ( i = 0; i < a->a_numvals; i++ ) {
+                       const char *text;
+
+                       rc = ordered_value_match( &match, a->a_desc, mr, flags,
+                               &a->a_nvals[i], cval, &text );
+                       if ( rc == LDAP_SUCCESS && match == 0 )
+                               break;
+               }
+       }
+       *slot = i;
+       if ( match )
+               rc = LDAP_NO_SUCH_ATTRIBUTE;
+       if ( nval.bv_val )
+               slap_sl_free( nval.bv_val, ctx );
+
+       return rc;
+}
+
 int
 attr_valadd(
        Attribute *a,
@@ -312,22 +380,52 @@ attr_valadd(
                a->a_nvals = a->a_vals;
        }
 
-       v2 = &a->a_vals[a->a_numvals];
-       for ( i = 0 ; i < nn; i++ ) {
-               ber_dupbv( &v2[i], &vals[i] );
-               if ( BER_BVISNULL( &v2[i] ) ) break;
-       }
-       BER_BVZERO( &v2[i] );
-
-       if ( nvals ) {
-               v2 = &a->a_nvals[a->a_numvals];
+       /* If sorted and old vals exist, must insert */
+       if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && a->a_numvals ) {
+               unsigned slot;
+               int j, rc;
+               v2 = nvals ? nvals : vals;
+               for ( i = 0; i < nn; i++ ) {
+                       rc = attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
+                               SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
+                               &v2[i], &slot, NULL );
+                       if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) {
+                               /* should never happen */
+                               if ( rc == LDAP_SUCCESS )
+                                       rc = LDAP_TYPE_OR_VALUE_EXISTS;
+                               return rc;
+                       }
+                       for ( j = a->a_numvals; j > slot; j-- ) {
+                               a->a_vals[j+1] = a->a_vals[j];
+                               if ( nvals )
+                                       a->a_nvals[j+1] = a->a_nvals[j];
+                       }
+                       ber_dupbv( &a->a_nvals[j], &v2[i] );
+                       if ( nvals )
+                               ber_dupbv( &a->a_vals[j], &vals[i] );
+                       a->a_numvals++;
+               }
+               BER_BVZERO( &a->a_vals[a->a_numvals] );
+               if ( a->a_vals != a->a_nvals )
+                       BER_BVZERO( &a->a_nvals[a->a_numvals] );
+       } else {
+               v2 = &a->a_vals[a->a_numvals];
                for ( i = 0 ; i < nn; i++ ) {
-                       ber_dupbv( &v2[i], &nvals[i] );
+                       ber_dupbv( &v2[i], &vals[i] );
                        if ( BER_BVISNULL( &v2[i] ) ) break;
                }
                BER_BVZERO( &v2[i] );
+
+               if ( nvals ) {
+                       v2 = &a->a_nvals[a->a_numvals];
+                       for ( i = 0 ; i < nn; i++ ) {
+                               ber_dupbv( &v2[i], &nvals[i] );
+                               if ( BER_BVISNULL( &v2[i] ) ) break;
+                       }
+                       BER_BVZERO( &v2[i] );
+               }
+               a->a_numvals += i;
        }
-       a->a_numvals += i;
        return 0;
 }
 
index 96ad30996755c7393c6757c4d5ce8280639fa3c3..2271940de1eb18680a3f2c7a558061a584459194 100644 (file)
@@ -210,6 +210,7 @@ bdb_monitor_free(
        mod.sm_op = LDAP_MOD_DELETE;
        mod.sm_desc = slap_schema.si_ad_objectClass;
        mod.sm_values = values;
+       mod.sm_numvals = 1;
        values[ 0 ] = oc_olmBDBDatabase->soc_cname;
        BER_BVZERO( &values[ 1 ] );
 
@@ -218,9 +219,10 @@ bdb_monitor_free(
        /* don't care too much about return code... */
 
        /* remove attrs */
+       mod.sm_values = NULL;
+       mod.sm_numvals = 0;
        for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
                mod.sm_desc = *s_at[ i ].ad;
-               mod.sm_values = NULL;
                rc = modify_delete_values( e, &mod, 1, &text,
                        textbuf, sizeof( textbuf ) );
                /* don't care too much about return code... */
index 6a6e56d61f4f28acc943c92c712edef099494c5d..d83ac375203cc2328f6bfec63da8217e018d3821 100644 (file)
@@ -177,6 +177,7 @@ enum {
        CFG_HIDDEN,
        CFG_MONITORING,
        CFG_SERVERID,
+       CFG_SORTVALS,
 
        CFG_LAST
 };
@@ -552,6 +553,11 @@ static ConfigTable config_back_cf_table[] = {
        { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T,
                &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' "
                        "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+       { "sortvals", "attr", 2, 0, 0, ARG_MAGIC|CFG_SORTVALS,
+               &config_generic, "( OLcfgGlAt:83 NAME 'olcSortVals' "
+                       "DESC 'Attributes whose values will always be sorted' "
+                       "EQUALITY caseIgnoreMatch "
+                       "SYNTAX OMsDirectoryString )", NULL, NULL },
        { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC,
                &config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' "
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
@@ -765,7 +771,7 @@ static ConfigOCs cf_ocs[] = {
                "NAME 'olcFrontendConfig' "
                "DESC 'OpenLDAP frontend configuration' "
                "AUXILIARY "
-               "MAY ( olcDefaultSearchBase $ olcPasswordHash ) )",
+               "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )",
                Cft_Database, NULL, NULL },
 #ifdef SLAPD_MODULES
        { "( OLcfgGlOc:8 "
@@ -786,6 +792,13 @@ typedef struct ServerID {
 
 static ServerID *sid_list;
 
+typedef struct ADlist {
+       struct ADlist *al_next;
+       AttributeDescription *al_desc;
+} ADlist;
+
+static ADlist *sortVals;
+
 static int
 config_generic(ConfigArgs *c) {
        int i;
@@ -1000,6 +1013,14 @@ config_generic(ConfigArgs *c) {
                case CFG_SSTR_IF_MIN:
                        c->value_int = index_substr_if_minlen;
                        break;
+               case CFG_SORTVALS: {
+                       ADlist *sv;
+                       rc = 1;
+                       for ( sv = sortVals; sv; sv = sv->al_next ) {
+                               value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname );
+                               rc = 0;
+                       }
+                       } break;
 #ifdef SLAPD_MODULES
                case CFG_MODLOAD: {
                        ModPaths *mp = c->private;
@@ -1224,6 +1245,27 @@ config_generic(ConfigArgs *c) {
                                }
                        }
                        break;
+               case CFG_SORTVALS:
+                       if ( c->valx < 0 ) {
+                               ADlist *sv;
+                               for ( sv = sortVals; sv; sv = sortVals ) {
+                                       sortVals = sv->al_next;
+                                       sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
+                                       ch_free( sv );
+                               }
+                       } else {
+                               ADlist *sv, **prev;
+                               int i = 0;
+
+                               for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) {
+                                       prev = &sv->al_next;
+                                       sv = sv->al_next;
+                               }
+                               sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
+                               *prev = sv->al_next;
+                               ch_free( sv );
+                       }
+                       break;
 
                case CFG_LIMITS:
                        /* FIXME: there is no limits_free function */
@@ -1447,6 +1489,52 @@ config_generic(ConfigArgs *c) {
                                        return(1);
                        break;
 
+               case CFG_SORTVALS: {
+                       ADlist *svnew = NULL, *svtail, *sv;
+
+                       for ( i = 1; i < c->argc; i++ ) {
+                               AttributeDescription *ad = NULL;
+                               const char *text;
+                               int rc;
+
+                               rc = slap_str2ad( c->argv[i], &ad, &text );
+                               if ( rc ) {
+                                       snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d",
+                                               c->argv[0], i );
+sortval_reject:
+                                       Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
+                                               c->log, c->cr_msg, c->argv[i] );
+                                       for ( sv = svnew; sv; sv = svnew ) {
+                                               svnew = sv->al_next;
+                                               ch_free( sv );
+                                       }
+                                       return 1;
+                               }
+                               if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) ||
+                                       ad->ad_type->sat_single_value ) {
+                                       snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d",
+                                               c->argv[0], i );
+                                       goto sortval_reject;
+                               }
+                               sv = ch_malloc( sizeof( ADlist ));
+                               sv->al_desc = ad;
+                               if ( !svnew ) {
+                                       svnew = sv;
+                               } else {
+                                       svtail->al_next = sv;
+                               }
+                               svtail = sv;
+                       }
+                       for ( sv = svnew; sv; sv = sv->al_next )
+                               sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL;
+                       for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next );
+                       if ( sv )
+                               sv->al_next = svnew;
+                       else
+                               sortVals = svnew;
+                       }
+                       break;
+
                case CFG_ACL:
                        /* Don't append to the global ACL if we're on a specific DB */
                        i = c->valx;
@@ -4544,7 +4632,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                         */
                        if ( ct && ml->sml_values ) {
                                delrec *d;
-                               for (i=0; ml->sml_values[i].bv_val; i++);
+                               i = ml->sml_numvals;
                                d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int));
                                d->nidx = i;
                                d->next = NULL;
@@ -4577,8 +4665,7 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
                                if ( ct->arg_type & ARG_NO_INSERT ) {
                                        Attribute *a = attr_find( e->e_attrs, ml->sml_desc );
                                        if ( a ) {
-                                               for (i = 0; a->a_vals[i].bv_val; i++ );
-                                               navals = i;
+                                               navals = a->a_numvals;
                                        }
                                }
                                for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) {
index 3e868cc811ffe9a66746c3d2c9dc74cca8c478fb..ff03e8203fc492df16d6d398691af75c9c7a837d 100644 (file)
@@ -277,6 +277,18 @@ str2entry2( char *s, int checkvals )
 
                if (( ad_prev && ad != ad_prev ) || ( i == lines )) {
                        int j, k;
+                       /* FIXME: we only need this when migrating from an unsorted DB */
+                       if ( atail != &ahead && atail->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
+                               rc = slap_sort_vals( (Modifications *)atail, &text, &j, NULL );
+                               if ( rc == LDAP_SUCCESS ) {
+                                       atail->a_flags |= SLAP_ATTR_SORTED_VALS;
+                               } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+                                       Debug( LDAP_DEBUG_ANY,
+                                               "str2entry: attributeType %s value #%d provided more than once\n",
+                                               atail->a_desc->ad_cname.bv_val, j, 0 );
+                                       goto fail;
+                               }
+                       }
                        atail->a_next = attr_alloc( NULL );
                        atail = atail->a_next;
                        atail->a_flags = 0;
@@ -892,6 +904,19 @@ int entry_decode(EntryHeader *eh, Entry **e)
                } else {
                        a->a_nvals = a->a_vals;
                }
+               /* FIXME: This is redundant once a sorted entry is saved into the DB */
+               if ( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
+                       rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
+                       if ( rc == LDAP_SUCCESS ) {
+                               a->a_flags |= SLAP_ATTR_SORTED_VALS;
+                       } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+                               /* should never happen */
+                               Debug( LDAP_DEBUG_ANY,
+                                       "entry_decode: attributeType %s value #%d provided more than once\n",
+                                       a->a_desc->ad_cname.bv_val, j, 0 );
+                               return rc;
+                       }
+               }
                a = a->a_next;
                nattrs--;
                if ( !nattrs )
index f3948d4e33b0f6cf922f88e472b5e6bccf288dc8..d0282b16e6039ca45b70e5303eab6cd78aaf2624 100644 (file)
@@ -640,200 +640,200 @@ int slap_mods_check(
                        /* check for duplicates, but ignore Deletes.
                         */
                        if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
-#define        SLAP_MODS_CHECK_QUICKSORT
-#ifndef SLAP_MODS_CHECK_QUICKSORT
-                               int             i, j, rc, match;
-                               MatchingRule *mr = ad->ad_type->sat_equality;
-
-                               for ( i = 1; i < nvals ; i++ ) {
-                                       /* test asserted values against themselves */
-                                       for( j = 0; j < i; j++ ) {
-                                               rc = ordered_value_match( &match, ml->sml_desc, mr,
-                                                       SLAP_MR_EQUALITY
-                                                               | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
-                                                               | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
-                                                               | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                                                       ml->sml_nvalues
-                                                               ? &ml->sml_nvalues[i]
-                                                               : &ml->sml_values[i],
-                                                       ml->sml_nvalues
-                                                               ? &ml->sml_nvalues[j]
-                                                               : &ml->sml_values[j],
-                                                       text );
-                                               if ( rc == LDAP_SUCCESS && match == 0 ) {
-                                                       /* value exists already */
-                                                       snprintf( textbuf, textlen,
-                                                               "%s: value #%d provided more than once",
-                                                               ml->sml_desc->ad_cname.bv_val, j );
-                                                       *text = textbuf;
-                                                       return LDAP_TYPE_OR_VALUE_EXISTS;
-
-                                               } else if ( rc != LDAP_SUCCESS ) {
-                                                       return rc;
-                                               }
-                                       }
+                               int i;
+                               rc = slap_sort_vals( ml, text, &i, ctx );
+                               if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+                                       /* value exists already */
+                                       snprintf( textbuf, textlen,
+                                               "%s: value #%d provided more than once",
+                                               ml->sml_desc->ad_cname.bv_val, i );
+                                       *text = textbuf;
                                }
-#else  /* SLAP_MODS_CHECK_QUICKSORT */
+                               if ( rc )
+                                       return rc;
+                       }
+               } else {
+                       ml->sml_numvals = 0;
+               }
+       }
+
+       return LDAP_SUCCESS;
+}
+
+/* Sort a set of values. An (Attribute *) may be used interchangeably here
+ * instead of a (Modifications *) structure.
+ *
+ * Uses Quicksort + Insertion sort for small arrays
+ */
 
-/* Quicksort + Insertion sort for small arrays */
+int
+slap_sort_vals(
+       Modifications *ml,
+       const char **text,
+       int *dup,
+       void *ctx )
+{
+       AttributeDescription *ad;
+       MatchingRule *mr;
+       int istack[sizeof(int)*16];
+       int i, j, k, l, ir, jstack, match, *ix, itmp, nvals, rc;
+       int is_norm;
+       struct berval a, *cv;
 
 #define SMALL  8
 #define        SWAP(a,b,tmp)   tmp=(a);(a)=(b);(b)=tmp
 #define        COMP(a,b)       match=0; rc = ordered_value_match( &match, \
-                                               ml->sml_desc, mr, SLAP_MR_EQUALITY \
+                                               ad, mr, SLAP_MR_EQUALITY \
                                                                | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX \
                                                                | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \
                                                                | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \
                                                                &(a), &(b), text );
 
-                                       MatchingRule *mr = ad->ad_type->sat_equality;
-                                       int istack[sizeof(int)*16];
-                                       int i, j, k, l, ir, jstack, match, *ix, itmp;
-                                       struct berval a, *cv;
-
-/* If PRESERVE_ORDER is defined only the index array is sorted; the
- * actual values are left in their incoming order. Otherwise, the
- * only reason to keep the index array is to identify the offending
- * value when duplicates are found.
- */
-#define        PRESERVE_ORDER
-#ifndef PRESERVE_ORDER
-                                       struct berval va, *v, *nv, bvtmp;
-
-#define        IX(x)   x
-#define        EXCH(x,y)       SWAP(ix[x],ix[y],itmp); SWAP(cv[x],cv[y],bvtmp); \
-       if (nv) {SWAP(v[x],v[y],bvtmp);}
-#define        SETA(x) itmp = ix[x]; a = cv[x]; if (nv) va=v[x]
-#define        GETA(x) ix[x] = itmp; cv[x] = a; if (nv) v[x]=va
-#define        SET(x,y)        ix[x] = ix[y]; cv[x] = cv[y]; if (nv) v[x]=v[y]
-
-                                       v = ml->sml_values;
-                                       nv = ml->sml_nvalues;
-
-#else  /* PRESERVE_ORDER */
-
 #define        IX(x)   ix[x]
 #define        EXCH(x,y)       SWAP(ix[x],ix[y],itmp)
 #define        SETA(x) itmp = ix[x]; a = cv[itmp]
 #define        GETA(x) ix[x] = itmp;
 #define        SET(x,y)        ix[x] = ix[y]
 
-#endif /* PRESERVE_ORDER */
-
-                                       cv = ml->sml_nvalues ? ml->sml_nvalues : ml->sml_values;
-                                       if ( ad == slap_schema.si_ad_objectClass )
-                                               mr = NULL;      /* shortcut matching */
-
-                                       /* record indices to preserve input ordering */
-                                       ix = slap_sl_malloc( nvals * sizeof(int), ctx );
-                                       for (i=0; i<nvals; i++) ix[i] = i;
-
-                                       ir = nvals-1;
-                                       l = 0;
-                                       jstack = 0;
-
-                                       for(;;) {
-                                               if (ir - l < SMALL) {   /* Insertion sort */
-                                                       match=1;
-                                                       for (j=l+1;j<=ir;j++) {
-                                                               SETA(j);
-                                                               for (i=j-1;i>=0;i--) {
-                                                                       COMP(cv[IX(i)], a);
-                                                                       if ( match <= 0 )
-                                                                               break;
-                                                                       SET(i+1,i);
-                                                               }
-                                                               GETA(i+1);
-                                                               if ( match == 0 ) goto done;
-                                                       }
-                                                       if ( jstack == 0 ) break;
-                                                       if ( match == 0 ) break;
-                                                       ir = istack[jstack--];
-                                                       l = istack[jstack--];
-                                               } else {
-                                                       k = (l + ir) >> 1;      /* Choose median of left, center, right */
-                                                       EXCH(k, l+1);
-                                                       COMP( cv[IX(l)], cv[IX(ir)] );
-                                                       if ( match > 0 ) {
-                                                               EXCH(l, ir);
-                                                       } else if ( match == 0 ) {
-                                                               i = ir;
-                                                               break;
-                                                       }
-                                                       COMP( cv[IX(l+1)], cv[IX(ir)] );
-                                                       if ( match > 0 ) {
-                                                               EXCH(l+1, ir);
-                                                       } else if ( match == 0 ) {
-                                                               i = ir;
-                                                               break;
-                                                       }
-                                                       COMP( cv[IX(l)], cv[IX(l+1)] );
-                                                       if ( match > 0 ) {
-                                                               EXCH(l, l+1);
-                                                       } else if ( match == 0 ) {
-                                                               i = l;
-                                                               break;
-                                                       }
-                                                       i = l+1;
-                                                       j = ir;
-                                                       a = cv[IX(i)];
-                                                       for(;;) {
-                                                               do {
-                                                                       i++;
-                                                                       COMP( cv[IX(i)], a );
-                                                               } while( match < 0 );
-                                                               while( match > 0 ) {
-                                                                       j--;
-                                                                       COMP( cv[IX(j)], a );
-                                                               }
-                                                               if (j < i) {
-                                                                       match = 1;
-                                                                       break;
-                                                               }
-                                                               if ( match == 0 ) {
-                                                                       i = l+1;
-                                                                       break;
-                                                               }
-                                                               EXCH(i,j);
-                                                       }
-                                                       if ( match == 0 )
-                                                               break;
-                                                       EXCH(l+1,j);
-                                                       jstack += 2;
-                                                       if (ir-i+1 >= j) {
-                                                               istack[jstack] = ir;
-                                                               istack[jstack-1] = i;
-                                                               ir = j;
-                                                       } else {
-                                                               istack[jstack] = j;
-                                                               istack[jstack-1] = l;
-                                                               l = i;
-                                               }
-                                       }
-                               }
-done:
-                               if ( i >= 0 )
-                                       j = ix[i];
+       ad = ml->sml_desc;
+       nvals = ml->sml_numvals;
 
-                               slap_sl_free( ix, ctx );
+       /* For Modifications, sml_nvalues is NULL if normalization wasn't needed.
+        * For Attributes, sml_nvalues == sml_values when normalization isn't needed.
+        */
+       if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) {
+               cv = ml->sml_nvalues;
+               is_norm = 1;
+       } else {
+               cv = ml->sml_values;
+               is_norm = 0;
+       }
 
-                               if ( rc != LDAP_SUCCESS ) {
-                                       return rc;
-                               } else if ( match == 0 ) {
-                                       /* value exists already */
-                                       assert( i >= 0 );
-                                       assert( i < nvals );
-                                       snprintf( textbuf, textlen,
-                                               "%s: value #%d provided more than once",
-                                               ml->sml_desc->ad_cname.bv_val, j );
-                                       *text = textbuf;
-                                       return LDAP_TYPE_OR_VALUE_EXISTS;
+       if ( ad == slap_schema.si_ad_objectClass )
+               mr = NULL;      /* shortcut matching */
+       else
+               mr = ad->ad_type->sat_equality;
+
+       /* record indices to preserve input ordering */
+       ix = slap_sl_malloc( nvals * sizeof(int), ctx );
+       for (i=0; i<nvals; i++) ix[i] = i;
+
+       ir = nvals-1;
+       l = 0;
+       jstack = 0;
+
+       for(;;) {
+               if (ir - l < SMALL) {   /* Insertion sort */
+                       match=1;
+                       for (j=l+1;j<=ir;j++) {
+                               SETA(j);
+                               for (i=j-1;i>=0;i--) {
+                                       COMP(cv[IX(i)], a);
+                                       if ( match <= 0 )
+                                               break;
+                                       SET(i+1,i);
+                               }
+                               GETA(i+1);
+                               if ( match == 0 ) goto done;
+                       }
+                       if ( jstack == 0 ) break;
+                       if ( match == 0 ) break;
+                       ir = istack[jstack--];
+                       l = istack[jstack--];
+               } else {
+                       k = (l + ir) >> 1;      /* Choose median of left, center, right */
+                       EXCH(k, l+1);
+                       COMP( cv[IX(l)], cv[IX(ir)] );
+                       if ( match > 0 ) {
+                               EXCH(l, ir);
+                       } else if ( match == 0 ) {
+                               i = ir;
+                               break;
+                       }
+                       COMP( cv[IX(l+1)], cv[IX(ir)] );
+                       if ( match > 0 ) {
+                               EXCH(l+1, ir);
+                       } else if ( match == 0 ) {
+                               i = ir;
+                               break;
+                       }
+                       COMP( cv[IX(l)], cv[IX(l+1)] );
+                       if ( match > 0 ) {
+                               EXCH(l, l+1);
+                       } else if ( match == 0 ) {
+                               i = l;
+                               break;
+                       }
+                       i = l+1;
+                       j = ir;
+                       a = cv[IX(i)];
+                       for(;;) {
+                               do {
+                                       i++;
+                                       COMP( cv[IX(i)], a );
+                               } while( match < 0 );
+                               while( match > 0 ) {
+                                       j--;
+                                       COMP( cv[IX(j)], a );
+                               }
+                               if (j < i) {
+                                       match = 1;
+                                       break;
+                               }
+                               if ( match == 0 ) {
+                                       i = l+1;
+                                       break;
                                }
-#endif /* SLAP_MODS_CHECK_QUICKSORT */
+                               EXCH(i,j);
+                       }
+                       if ( match == 0 )
+                               break;
+                       EXCH(l+1,j);
+                       jstack += 2;
+                       if (ir-i+1 >= j) {
+                               istack[jstack] = ir;
+                               istack[jstack-1] = i;
+                               ir = j;
+                       } else {
+                               istack[jstack] = j;
+                               istack[jstack-1] = l;
+                               l = i;
                        }
                }
        }
+       done:
+       if ( i >= 0 )
+               *dup = ix[i];
+
+       /* For sorted attributes, put the values in index order */
+       if ( rc == LDAP_SUCCESS && match &&
+               ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) {
+               BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx );
+               for ( i = 0; i<nvals; i++ )
+                       tmpv[i] = cv[ix[i]];
+               for ( i = 0; i<nvals; i++ )
+                       cv[i] = tmpv[i];
+               /* Check if the non-normalized array needs to move too */
+               if ( is_norm ) {
+                       cv = ml->sml_values;
+                       for ( i = 0; i<nvals; i++ )
+                               tmpv[i] = cv[ix[i]];
+                       for ( i = 0; i<nvals; i++ )
+                               cv[i] = tmpv[i];
+               }
+               slap_sl_free( tmpv, ctx );
+       }
+
+       slap_sl_free( ix, ctx );
 
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       } else if ( match == 0 ) {
+               /* value exists already */
+               assert( i >= 0 );
+               assert( i < nvals );
+               return LDAP_TYPE_OR_VALUE_EXISTS;
+       }
        return LDAP_SUCCESS;
 }
 
index bfc0cd76e63256d1a2b6933bbb108a8bce6ce764..cbb1d70300b1b760ccf59eb3419517a93601b4a3 100644 (file)
@@ -56,11 +56,21 @@ modify_add_values(
                assert( 0 );
        }
 
+       /* FIXME: Catch old code that doesn't set sm_numvals.
+        */
+       if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) {
+               int i;
+               for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ );
+               assert( mod->sm_numvals == i );
+       }
+
        /* check if values to add exist in attribute */
        a = attr_find( e->e_attrs, mod->sm_desc );
        if ( a != NULL ) {
-               int             rc, i, j, p;
                MatchingRule    *mr;
+               struct berval *cvals;
+               int             rc, i, j, p;
+               unsigned flags;
 
                mr = mod->sm_desc->ad_type->sat_equality;
                if( mr == NULL || !mr->smr_match ) {
@@ -74,10 +84,7 @@ modify_add_values(
                }
 
                if ( permissive ) {
-                       for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
-                               /* EMPTY -- just counting 'em */;
-                       }
-
+                       i = mod->sm_numvals;
                        pmod.sm_values = (BerVarray)ch_malloc(
                                (i + 1) * sizeof( struct berval ));
                        if ( pmod.sm_nvalues != NULL ) {
@@ -92,39 +99,32 @@ modify_add_values(
                 * server (whether from LDAP or from the underlying
                 * database).
                 */
-               for ( p = i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
-                       int     match;
-
-                       assert( a->a_vals[0].bv_val != NULL );
-                       for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) {
-                               if ( mod->sm_nvalues ) {
-                                       rc = ordered_value_match( &match, mod->sm_desc, mr,
-                                               SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
-                                                       | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
-                                                       | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                                               &a->a_nvals[j], &mod->sm_nvalues[i], text );
-                               } else {
-                                       rc = ordered_value_match( &match, mod->sm_desc, mr,
-                                               SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
-                                               &a->a_vals[j], &mod->sm_values[i], text );
-                               }
+               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX;
+               if ( mod->sm_nvalues ) {
+                       flags |= SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
+                               SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH;
+                       cvals = mod->sm_nvalues;
+               } else {
+                       cvals = mod->sm_values;
+               }
+               for ( p = i = 0; i < mod->sm_numvals; i++ ) {
+                       unsigned        slot;
 
-                               if ( rc == LDAP_SUCCESS && match == 0 ) {
+                       rc = attr_valfind( a, flags, &cvals[i], &slot, NULL );
+                       if ( rc == LDAP_SUCCESS ) {
+                               if ( !permissive ) {
                                        /* value already exists */
-                                       if ( permissive ) break;
-
                                        *text = textbuf;
                                        snprintf( textbuf, textlen,
                                                "modify/%s: %s: value #%d already exists",
                                                op, mod->sm_desc->ad_cname.bv_val, i );
                                        return LDAP_TYPE_OR_VALUE_EXISTS;
-
-                               } else if ( rc != LDAP_SUCCESS ) {
-                                       return rc;
                                }
+                       } else if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) {
+                               return rc;
                        }
 
-                       if ( permissive && match != 0 ) {
+                       if ( permissive && rc ) {
                                if ( pmod.sm_nvalues ) {
                                        pmod.sm_nvalues[p] = mod->sm_nvalues[i];
                                }
@@ -164,8 +164,8 @@ modify_add_values(
                /* this should return result of attr_merge */
                *text = textbuf;
                snprintf( textbuf, textlen,
-                       "modify/%s: %s: merge error",
-                       op, mod->sm_desc->ad_cname.bv_val );
+                       "modify/%s: %s: merge error (%d)",
+                       op, mod->sm_desc->ad_cname.bv_val, rc );
                return LDAP_OTHER;
        }
 
@@ -192,11 +192,13 @@ modify_delete_vindex(
        char *textbuf, size_t textlen,
        int *idx )
 {
-       int             i, j, k, rc = LDAP_SUCCESS;
        Attribute       *a;
        MatchingRule    *mr = mod->sm_desc->ad_type->sat_equality;
+       struct berval *cvals;
+       int             *id2 = NULL;
+       int             i, j, rc;
+       unsigned flags;
        char            dummy = '\0';
-       int             match = 0;
 
        /*
         * If permissive is set, then the non-existence of an 
@@ -219,6 +221,17 @@ modify_delete_vindex(
                return rc;
        }
 
+       /* FIXME: Catch old code that doesn't set sm_numvals.
+        */
+       if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) {
+               for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ );
+               assert( mod->sm_numvals == i );
+       }
+       if ( !idx ) {
+               id2 = ch_malloc( mod->sm_numvals * sizeof( int ));
+               idx = id2;
+       }
+
        if( mr == NULL || !mr->smr_match ) {
                /* disallow specific attributes from being deleted if
                        no equality rule */
@@ -226,102 +239,90 @@ modify_delete_vindex(
                snprintf( textbuf, textlen,
                        "modify/delete: %s: no equality matching rule",
                        mod->sm_desc->ad_cname.bv_val );
-               return LDAP_INAPPROPRIATE_MATCHING;
+               rc = LDAP_INAPPROPRIATE_MATCHING;
+               goto return_result;
        }
 
        /* delete specific values - find the attribute first */
        if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
                if( permissive ) {
-                       return LDAP_SUCCESS;
+                       rc = LDAP_SUCCESS;
+                       goto return_result;
                }
                *text = textbuf;
                snprintf( textbuf, textlen,
                        "modify/delete: %s: no such attribute",
                        mod->sm_desc->ad_cname.bv_val );
-               return LDAP_NO_SUCH_ATTRIBUTE;
+               rc = LDAP_NO_SUCH_ATTRIBUTE;
+               goto return_result;
        }
 
-       for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
-               int     found = 0;
-               for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) {
-                       /* skip already deleted values */
-                       if ( a->a_vals[j].bv_val == &dummy ) {
-                               continue;
-                       }
-
-                       if( mod->sm_nvalues ) {
-                               assert( a->a_nvals != NULL );
-                               rc = ordered_value_match( &match, a->a_desc, mr,
-                                       SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
-                                               | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
-                                               | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                                       &a->a_nvals[j], &mod->sm_nvalues[i], text );
-                       } else {
-#if 0
-                               assert( a->a_nvals == NULL );
-#endif
-                               rc = ordered_value_match( &match, a->a_desc, mr,
-                                       SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
-                                       &a->a_vals[j], &mod->sm_values[i], text );
-                       }
-
-                       if ( rc != LDAP_SUCCESS ) {
-                               *text = textbuf;
-                               snprintf( textbuf, textlen,
-                                       "%s: matching rule failed",
-                                       mod->sm_desc->ad_cname.bv_val );
-                               break;
-                       }
+       if ( mod->sm_nvalues ) {
+               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
+                       | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
+                       | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH;
+               cvals = mod->sm_nvalues;
+       } else {
+               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX;
+               cvals = mod->sm_values;
+       }
 
-                       if ( match != 0 ) {
+       /* Locate values to delete */
+       for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
+               unsigned sort;
+               rc = attr_valfind( a, flags, &cvals[i], &sort, NULL );
+               if ( rc == LDAP_SUCCESS ) {
+                       idx[i] = sort;
+               } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
+                       if ( permissive ) {
+                               idx[i] = -1;
                                continue;
                        }
-
-                       found = 1;
-
-                       if ( idx )
-                               idx[i] = j;
-
-                       /* delete value and mark it as dummy */
-                       free( a->a_vals[j].bv_val );
-                       a->a_vals[j].bv_val = &dummy;
-                       if( a->a_nvals != a->a_vals ) {
-                               free( a->a_nvals[j].bv_val );
-                               a->a_nvals[j].bv_val = &dummy;
-                       }
-                       a->a_numvals--;
-
-                       break;
-               }
-
-               if ( found == 0 ) {
                        *text = textbuf;
                        snprintf( textbuf, textlen,
                                "modify/delete: %s: no such value",
                                mod->sm_desc->ad_cname.bv_val );
-                       rc = LDAP_NO_SUCH_ATTRIBUTE;
-                       if ( i > 0 ) {
-                               break;
-                       } else {
-                               goto return_results;
-                       }
+                       goto return_result;
+               } else {
+                       *text = textbuf;
+                       snprintf( textbuf, textlen,
+                               "modify/delete: %s: matching rule failed",
+                               mod->sm_desc->ad_cname.bv_val );
+                       goto return_result;
+               }
+       }
+
+       /* Delete the values */
+       for ( i = 0; i < mod->sm_numvals; i++ ) {
+               /* Skip permissive values that weren't found */
+               if ( idx[i] < 0 )
+                       continue;
+               /* Skip duplicate delete specs */
+               if ( a->a_vals[idx[i]].bv_val == &dummy )
+                       continue;
+               /* delete value and mark it as gone */
+               free( a->a_vals[idx[i]].bv_val );
+               a->a_vals[idx[i]].bv_val = &dummy;
+               if( a->a_nvals != a->a_vals ) {
+                       free( a->a_nvals[idx[i]].bv_val );
+                       a->a_nvals[idx[i]].bv_val = &dummy;
                }
+               a->a_numvals--;
        }
 
        /* compact array skipping dummies */
-       for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); k++ ) {
+       for ( i = 0, j = 0; !BER_BVISNULL( &a->a_vals[i] ); i++ ) {
                /* skip dummies */
-               if( a->a_vals[k].bv_val == &dummy ) {
-                       assert( a->a_nvals[k].bv_val == &dummy );
+               if( a->a_vals[i].bv_val == &dummy ) {
+                       assert( a->a_nvals[i].bv_val == &dummy );
                        continue;
                }
-               if ( j != k ) {
-                       a->a_vals[ j ] = a->a_vals[ k ];
+               if ( j != i ) {
+                       a->a_vals[ j ] = a->a_vals[ i ];
                        if (a->a_nvals != a->a_vals) {
-                               a->a_nvals[ j ] = a->a_nvals[ k ];
+                               a->a_nvals[ j ] = a->a_nvals[ i ];
                        }
                }
-
                j++;
        }
 
@@ -331,8 +332,9 @@ modify_delete_vindex(
        }
 
        /* if no values remain, delete the entire attribute */
-       if ( BER_BVISNULL( &a->a_vals[0] ) ) {
+       if ( !a->a_numvals ) {
                if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
+                       /* Can never happen */
                        *text = textbuf;
                        snprintf( textbuf, textlen,
                                "modify/delete: %s: no such attribute",
@@ -343,9 +345,9 @@ modify_delete_vindex(
                /* For an ordered attribute, renumber the value indices */
                ordered_value_sort( a, 1 );
        }
-
-return_results:;
-
+return_result:
+       if ( id2 )
+               ch_free( id2 );
        return rc;
 }
 
index 7e8a50ca3be46dadc7085581c589d21d2ebed3ae..1b58fe4bef6cf7e046c79a6d9e8fca4dafb4d07d 100644 (file)
@@ -189,6 +189,7 @@ dynlist_sc_update( Operation *op, SlapReply *rs )
                        mod.sm_type = dlc->dlc_dli->dli_member_ad->ad_cname;
                        mod.sm_values = vals;
                        mod.sm_nvalues = nvals;
+                       mod.sm_numvals = 1;
 
                        (void)modify_add_values( e, &mod, /* permissive */ 1,
                                        &text, textbuf, sizeof( textbuf ) );
@@ -292,6 +293,7 @@ dynlist_sc_update( Operation *op, SlapReply *rs )
                        mod.sm_type = a->a_desc->ad_cname;
                        mod.sm_values = vals;
                        mod.sm_nvalues = nvals;
+                       mod.sm_numvals = j;
 
                        (void)modify_add_values( e, &mod, /* permissive */ 1,
                                        &text, textbuf, sizeof( textbuf ) );
index 7d56d9789ef0fead99ed40a1cf3f99182195d6c0..40cf08b93026a3bd6e26c46360a409737ff0fcc9 100644 (file)
@@ -416,6 +416,7 @@ memberof_value_modify(
        op2.o_ndn = op->o_bd->be_rootndn;
 
        ml = &mod[ 0 ];
+       ml->sml_numvals = 1;
        ml->sml_values = &values[ 0 ];
        ml->sml_values[ 0 ] = mo->mo_dn;
        BER_BVZERO( &ml->sml_values[ 1 ] );
@@ -430,6 +431,7 @@ memberof_value_modify(
        op2.orm_modlist = ml;
 
        ml = &mod[ 1 ];
+       ml->sml_numvals = 1;
        ml->sml_values = &values[ 2 ];
        BER_BVZERO( &ml->sml_values[ 1 ] );
        ml->sml_nvalues = &nvalues[ 2 ];
@@ -812,6 +814,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                BER_BVZERO( &ml->sml_values[ i ] );
                                                ber_memfree( ml->sml_nvalues[ i ].bv_val );
                                                BER_BVZERO( &ml->sml_nvalues[ i ] );
+                                               ml->sml_numvals--;
                                                if ( j - i == 1 ) {
                                                        break;
                                                }
@@ -909,6 +912,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                                ber_memfree( ml->sml_nvalues[ i ].bv_val );
                                                                BER_BVZERO( &ml->sml_nvalues[ i ] );
                                                        }
+                                                       ml->sml_numvals--;
                                                        if ( j - i == 1 ) {
                                                                break;
                                                        }
@@ -1019,6 +1023,7 @@ memberof_op_modify( Operation *op, SlapReply *rs )
                                                        ber_memfree( ml->sml_nvalues[ i ].bv_val );
                                                        BER_BVZERO( &ml->sml_nvalues[ i ] );
                                                }
+                                               ml->sml_numvals--;
                                                if ( j - i == 1 ) {
                                                        break;
                                                }
index 72d2b330cc81b9ccd0a8c2c281b18dd71407d9f7..3cdcbf0c789eb4daac51a59c9a62f4f8ad29a566 100644 (file)
@@ -1287,6 +1287,7 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on )
        SlapReply rsm = { 0 };
        slap_callback cb = {0};
 
+       mod.sml_numvals = si->si_numcsns;
        mod.sml_values = si->si_ctxcsn;
        mod.sml_nvalues = NULL;
        mod.sml_desc = slap_schema.si_ad_contextCSN;
index 0dfce791c804053045ec5192530833af0fa5d6a7..fbbc9ae67535995552860bb2163c3f83d278082b 100644 (file)
@@ -268,6 +268,11 @@ LDAP_SLAPD_F (void) comp_tree_free LDAP_P(( Attribute *a ));
 LDAP_SLAPD_F (Attribute *) attr_alloc LDAP_P(( AttributeDescription *ad ));
 LDAP_SLAPD_F (Attribute *) attrs_alloc LDAP_P(( int num ));
 LDAP_SLAPD_F (int) attr_prealloc LDAP_P(( int num ));
+LDAP_SLAPD_F (int) attr_valfind LDAP_P(( Attribute *a,
+       unsigned flags,
+       struct berval *val,
+       unsigned *slot,
+       void *ctx ));
 LDAP_SLAPD_F (int) attr_valadd LDAP_P(( Attribute *a,
        BerVarray vals,
        BerVarray nvals,
@@ -1166,6 +1171,12 @@ LDAP_SLAPD_F( int ) slap_mods_check(
        const char **text,
        char *textbuf, size_t textlen, void *ctx );
 
+LDAP_SLAPD_F( int ) slap_sort_vals(
+       Modifications *ml,
+       const char **text,
+       int *dup,
+       void *ctx );
+
 LDAP_SLAPD_F( void ) slap_timestamp(
        time_t *tm,
        struct berval *bv );
index 77077481463b9a5dddc7668fab433a825ff5a7bf..bbcc3437b83f14481a71d54bab866dfd5f39903b 100644 (file)
@@ -690,10 +690,19 @@ struct AttributeType {
 
 #define SLAP_AT_MANAGEABLE             0x0800U /* no-user-mod can be by-passed */
 
+/* Note: ORDERED values have an ordering specifically set by the
+ * user, denoted by the {x} ordering prefix on the values.
+ *
+ * SORTED values are simply sorted by memcmp. SORTED values can
+ * be efficiently located by binary search. ORDERED values have no
+ * such advantage. An attribute cannot have both properties.
+ */
 #define        SLAP_AT_ORDERED_VAL             0x0001U /* values are ordered */
 #define        SLAP_AT_ORDERED_SIB             0x0002U /* siblings are ordered */
 #define        SLAP_AT_ORDERED                 0x0003U /* value has order index */
 
+#define        SLAP_AT_SORTED_VAL              0x0010U /* values should be sorted */
+
 #define        SLAP_AT_HARDCODE                0x10000U        /* hardcoded schema */
 #define        SLAP_AT_DELETED                 0x20000U
 
@@ -1109,22 +1118,23 @@ struct ValuesReturnFilter {
 
 /*
  * represents an attribute (description + values)
+ * desc, vals, nvals, numvals fields must align with Modification
  */
 struct Attribute {
        AttributeDescription    *a_desc;
        BerVarray               a_vals;         /* preserved values */
        BerVarray               a_nvals;        /* normalized values */
-#ifdef LDAP_COMP_MATCH
-       ComponentData           *a_comp_data;   /* component values */
-#endif
-       Attribute               *a_next;
        unsigned                a_numvals;      /* number of vals */
        unsigned                a_flags;
 #define SLAP_ATTR_IXADD                        0x1U
 #define SLAP_ATTR_IXDEL                        0x2U
 #define SLAP_ATTR_DONT_FREE_DATA       0x4U
 #define SLAP_ATTR_DONT_FREE_VALS       0x8U
-#define        SLAP_ATTR_SORTED_VALS           0x10U
+#define        SLAP_ATTR_SORTED_VALS           0x10U   /* values are sorted */
+       Attribute               *a_next;
+#ifdef LDAP_COMP_MATCH
+       ComponentData           *a_comp_data;   /* component values */
+#endif
 };
 
 
@@ -1171,8 +1181,13 @@ struct Entry {
 
 /*
  * A list of LDAPMods
+ * desc, values, nvalues, numvals must align with Attribute
  */
 struct Modification {
+       AttributeDescription *sm_desc;
+       BerVarray sm_values;
+       BerVarray sm_nvalues;
+       unsigned sm_numvals;
        short sm_op;
        short sm_flags;
 /* Set for internal mods, will bypass ACL checks. Only needed when
@@ -1180,12 +1195,7 @@ struct Modification {
  */
 #define        SLAP_MOD_INTERNAL       0x01
 #define        SLAP_MOD_MANAGING       0x02
-
-       AttributeDescription *sm_desc;
        struct berval sm_type;
-       BerVarray sm_values;
-       BerVarray sm_nvalues;
-       unsigned sm_numvals;
 };
 
 struct Modifications {
index f676e5402dba970b98a91dfbd8dda3df69fc757d..446fd80f4c453a8b7dc5e322cbd667bf44b262b1 100644 (file)
@@ -72,7 +72,8 @@ static int checkBVString(const struct berval *bv)
 int
 bvptr2obj(
        struct berval   **bvptr, 
-       BerVarray       *bvobj )
+       BerVarray       *bvobj,
+       unsigned *num )
 {
        int             rc = LDAP_SUCCESS;
        int             i;
@@ -85,6 +86,8 @@ bvptr2obj(
        for ( i = 0; bvptr != NULL && bvptr[i] != NULL; i++ ) {
                ; /* EMPTY */
        }
+       if ( num )
+               *num = i;
 
        tmpberval = (BerVarray)slapi_ch_malloc( (i + 1)*sizeof(struct berval));
        if ( tmpberval == NULL ) {
@@ -231,12 +234,12 @@ slapi_entry_attr_merge(
                return -1;
        }
        
-       rc = bvptr2obj( vals, &bv );
+       rc = bvptr2obj( vals, &bv, NULL );
        if ( rc != LDAP_SUCCESS ) {
                return -1;
        }
        
-       rc = attr_merge_normalize_one( e, ad, bv, NULL );
+       rc = attr_merge_normalize( e, ad, bv, NULL );
        ch_free( bv );
 
        return rc;
@@ -545,9 +548,10 @@ slapi_entry_add_values( Slapi_Entry *e, const char *type, struct berval **vals )
                 * FIXME: sm_values = NULL ? */
                mod.sm_values = (BerVarray)ch_malloc( sizeof(struct berval) );
                mod.sm_values->bv_val = NULL;
+               mod.sm_numvals = 0;
 
        } else {
-               rc = bvptr2obj( vals, &mod.sm_values );
+               rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals );
                if ( rc != LDAP_SUCCESS ) {
                        return LDAP_CONSTRAINT_VIOLATION;
                }
@@ -611,7 +615,7 @@ slapi_entry_delete_values( Slapi_Entry *e, const char *type, struct berval **val
                return attr_delete( &e->e_attrs, mod.sm_desc ) ? LDAP_OTHER : LDAP_SUCCESS;
        }
 
-       rc = bvptr2obj( vals, &mod.sm_values );
+       rc = bvptr2obj( vals, &mod.sm_values, &mod.sm_numvals );
        if ( rc != LDAP_SUCCESS ) {
                return LDAP_CONSTRAINT_VIOLATION;
        }
@@ -730,7 +734,7 @@ slapi_entry_attr_replace_sv( Slapi_Entry *e, const char *type, Slapi_Value **val
 
        attr_delete( &e->e_attrs, ad );
 
-       rc = bvptr2obj( vals, &bv );
+       rc = bvptr2obj( vals, &bv, NULL );
        if ( rc != LDAP_SUCCESS ) {
                return -1;
        }
@@ -1350,7 +1354,7 @@ slapi_send_ldap_result(
                if ( pb->pb_op->o_tag == LDAP_REQ_SEARCH )
                        rs->sr_nentries = nentries;
                if ( urls != NULL )
-                       bvptr2obj( urls, &rs->sr_ref );
+                       bvptr2obj( urls, &rs->sr_ref, NULL );
 
                send_ldap_result( pb->pb_op, rs );
 
@@ -1429,7 +1433,7 @@ slapi_send_ldap_search_reference(
        rs.sr_matched = NULL;
        rs.sr_text = NULL;
 
-       rc = bvptr2obj( references, &rs.sr_ref );
+       rc = bvptr2obj( references, &rs.sr_ref, NULL );
        if ( rc != LDAP_SUCCESS ) {
                return rc;
        }
@@ -1440,7 +1444,7 @@ slapi_send_ldap_search_reference(
        rs.sr_entry = e;
 
        if ( v2refs != NULL ) {
-               rc = bvptr2obj( v2refs, &rs.sr_v2ref );
+               rc = bvptr2obj( v2refs, &rs.sr_v2ref, NULL );
                if ( rc != LDAP_SUCCESS ) {
                        slapi_ch_free( (void **)&rs.sr_ref );
                        return rc;
index 2ab959c8589c8a415422cb0f6053c1e3934c5beb..ea94e4e2794c4f6148e6204c7b7f6fccd2f39cf9 100644 (file)
@@ -2567,6 +2567,7 @@ syncrepl_updateCookie(
        mod[0].sml_type = mod[0].sml_desc->ad_cname;
        mod[0].sml_values = NULL;
        mod[0].sml_nvalues = NULL;
+       mod[0].sml_numvals = 0;
        mod[0].sml_next = &mod[1];
 
        mod[1].sml_op = LDAP_MOD_ADD;
@@ -2574,6 +2575,7 @@ syncrepl_updateCookie(
        mod[1].sml_type = mod[0].sml_desc->ad_cname;
        mod[1].sml_values = NULL;
        mod[1].sml_nvalues = NULL;
+       mod[1].sml_numvals = 0;
        mod[1].sml_next = NULL;
 
        ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
@@ -2589,8 +2591,10 @@ syncrepl_updateCookie(
                                si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
                                ber_bvarray_add_x( &mod[0].sml_values,
                                        &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
+                               mod[0].sml_numvals++;
                                ber_bvarray_add_x( &mod[1].sml_values,
                                        &syncCookie->ctxcsn[i], op->o_tmpmemctx );
+                               mod[1].sml_numvals++;
                                if ( BER_BVISNULL( &first ))
                                        first = syncCookie->ctxcsn[i];
                        }
@@ -2600,6 +2604,7 @@ syncrepl_updateCookie(
                if ( j == si->si_cookieState->cs_num ) {
                        ber_bvarray_add_x( &mod[1].sml_values,
                                &syncCookie->ctxcsn[i], op->o_tmpmemctx );
+                       mod[1].sml_numvals++;
                        if ( BER_BVISNULL( &first ))
                                first = syncCookie->ctxcsn[i];
                }