]> git.sur5r.net Git - openldap/commitdiff
Generic ordered value support
authorHoward Chu <hyc@openldap.org>
Thu, 14 Apr 2005 10:31:51 +0000 (10:31 +0000)
committerHoward Chu <hyc@openldap.org>
Thu, 14 Apr 2005 10:31:51 +0000 (10:31 +0000)
servers/slapd/add.c
servers/slapd/at.c
servers/slapd/bconfig.c
servers/slapd/modify.c
servers/slapd/mods.c
servers/slapd/proto-slap.h
servers/slapd/value.c

index 39c11162f7d29b0d03c51f89651ca042fa46c48c..ada140c384376dfa99773559e47136840404144a 100644 (file)
@@ -504,56 +504,34 @@ slap_mods2entry(
 
                if( mods->sml_values[1].bv_val != NULL ) {
                        /* check for duplicates */
-                       int             i, j;
+                       int             i, j, rc, match;
                        MatchingRule *mr = mods->sml_desc->ad_type->sat_equality;
 
-                       /* check if the values we're adding already exist */
-                       if( mr == NULL || !mr->smr_match ) {
-                               for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
-                                       /* test asserted values against themselves */
-                                       for( j = 0; j < i; j++ ) {
-                                               if ( bvmatch( &mods->sml_values[i],
-                                                       &mods->sml_values[j] ) )
-                                               {
-                                                       /* value exists already */
-                                                       snprintf( textbuf, textlen,
-                                                               "%s: value #%d provided more than once",
-                                                               mods->sml_desc->ad_cname.bv_val, j );
-                                                       return LDAP_TYPE_OR_VALUE_EXISTS;
-                                               }
-                                       }
-                               }
-
-                       } else {
-                               int     rc;
-                               int match;
-
-                               for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
-                                       /* test asserted values against themselves */
-                                       for( j = 0; j < i; j++ ) {
-                                               rc = value_match( &match, mods->sml_desc, mr,
-                                                       SLAP_MR_EQUALITY
-                                                       | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
-                                                       | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
-                                                       | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
-                                                       mods->sml_nvalues
-                                                               ? &mods->sml_nvalues[i]
-                                                               : &mods->sml_values[i],
-                                                       mods->sml_nvalues
-                                                               ? &mods->sml_nvalues[j]
-                                                               : &mods->sml_values[j],
-                                                       text );
-
-                                               if ( rc == LDAP_SUCCESS && match == 0 ) {
-                                                       /* value exists already */
-                                                       snprintf( textbuf, textlen,
-                                                               "%s: value #%d provided more than once",
-                                                               mods->sml_desc->ad_cname.bv_val, j );
-                                                       return LDAP_TYPE_OR_VALUE_EXISTS;
-
-                                               } else if ( rc != LDAP_SUCCESS ) {
-                                                       return rc;
-                                               }
+                       for ( i = 1; mods->sml_values[i].bv_val != NULL; i++ ) {
+                               /* test asserted values against themselves */
+                               for( j = 0; j < i; j++ ) {
+                                       rc = ordered_value_match( &match, mods->sml_desc, mr,
+                                               SLAP_MR_EQUALITY
+                                               | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX
+                                               | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
+                                               | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
+                                               mods->sml_nvalues
+                                                       ? &mods->sml_nvalues[i]
+                                                       : &mods->sml_values[i],
+                                               mods->sml_nvalues
+                                                       ? &mods->sml_nvalues[j]
+                                                       : &mods->sml_values[j],
+                                               text );
+
+                                       if ( rc == LDAP_SUCCESS && match == 0 ) {
+                                               /* value exists already */
+                                               snprintf( textbuf, textlen,
+                                                       "%s: value #%d provided more than once",
+                                                       mods->sml_desc->ad_cname.bv_val, j );
+                                               return LDAP_TYPE_OR_VALUE_EXISTS;
+
+                                       } else if ( rc != LDAP_SUCCESS ) {
+                                               return rc;
                                        }
                                }
                        }
index 784f3974ca736e93ed49097e9952efbdfdebd43f..c0fec00e7ede5f265b0b105bdb131ad73fa71e03 100644 (file)
@@ -519,7 +519,9 @@ at_add(
        if ( sat->sat_extensions ) {
                for (i=0; sat->sat_extensions[i]; i++) {
                        if (!strcasecmp( sat->sat_extensions[i]->lsei_name,
-                               "X-ORDERED" )) {
+                               "X-ORDERED" ) && sat->sat_extensions[i]->lsei_values &&
+                               !strcasecmp( sat->sat_extensions[i]->lsei_values[0],
+                               "VALUES" )) {
                                sat->sat_flags |= SLAP_AT_ORDERED;
                                break;
                        }
index 28b74d8d1039d0de40eec86a59688a2ef97a27ab..797539b3d54d8ad449bd7ff8da02cf1c5c9ebc8b 100644 (file)
@@ -2884,87 +2884,6 @@ config_find_table( CfOcInfo **colst, int nocs, AttributeDescription *ad )
        return NULL;
 }
 
-/* Sort the values in an X-ORDERED VALUES attribute.
- * If the values have no index, leave them in their given order.
- * If the values have indexes, sort them.
- * If some are indexed and some are not, return Error.
- *
- * FIXME: This function probably belongs in the frontend somewhere,
- * like slap_mods_check.
- */
-static int
-sort_vals( Attribute *a )
-{
-       int i;
-       int index = 0, noindex = 0;
-
-       /* count attrs, look for index */
-       for (i=0; a->a_vals[i].bv_val; i++) {
-               if ( a->a_vals[i].bv_val[0] == '{' ) {
-                       char *ptr;
-                       index = 1;
-                       ptr = strchr( a->a_vals[i].bv_val, '}' );
-                       if ( !ptr || !ptr[1] )
-                               return LDAP_INVALID_SYNTAX;
-                       if ( noindex )
-                               return LDAP_INVALID_SYNTAX;
-               } else {
-                       noindex = 1;
-                       if ( index )
-                               return LDAP_INVALID_SYNTAX;
-               }
-       }
-
-       if ( index ) {
-               int vals = i, *indexes, j, idx;
-               struct berval tmp, ntmp;
-               char *ptr;
-
-#if 0
-               /* Strip index from normalized values */
-               if ( !a->a_nvals || a->a_vals == a->a_nvals ) {
-                       a->a_nvals = ch_malloc( (vals+1)*sizeof(struct berval));
-                       BER_BVZERO(a->a_nvals+vals);
-                       for ( i=0; i<vals; i++ ) {
-                               ptr = strchr(a->a_vals[i].bv_val, '}') + 1;
-                               a->a_nvals[i].bv_len = a->a_vals[i].bv_len -
-                                       (ptr - a->a_vals[i].bv_val);
-                               a->a_nvals[i].bv_val = ch_malloc( a->a_nvals[i].bv_len + 1);
-                               strcpy(a->a_nvals[i].bv_val, ptr );
-                       }
-               } else {
-                       for ( i=0; i<vals; i++ ) {
-                               ptr = strchr(a->a_nvals[i].bv_val, '}') + 1;
-                               a->a_nvals[i].bv_len -= ptr - a->a_nvals[i].bv_val;
-                               strcpy(a->a_nvals[i].bv_val, ptr);
-                       }
-               }
-#endif
-                               
-               indexes = ch_malloc( vals * sizeof(int) );
-               for ( i=0; i<vals; i++)
-                       indexes[i] = atoi(a->a_vals[i].bv_val+1);
-
-               /* Insertion sort */
-               for ( i=1; i<vals; i++ ) {
-                       idx = indexes[i];
-                       tmp = a->a_vals[i];
-                       ntmp = a->a_nvals[i];
-                       j = i;
-                       while ((j > 0) && (indexes[j-1] > idx)) {
-                               indexes[j] = indexes[j-1];
-                               a->a_vals[j] = a->a_vals[j-1];
-                               a->a_nvals[j] = a->a_nvals[j-1];
-                               j--;
-                       }
-                       indexes[j] = idx;
-                       a->a_vals[j] = tmp;
-                       a->a_nvals[j] = ntmp;
-               }
-       }
-       return 0;
-}
-
 /* Sort the attributes of the entry according to the order defined
  * in the objectclass, with required attributes occurring before
  * allowed attributes. For any attributes with sequencing dependencies
@@ -3044,7 +2963,7 @@ check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
 
        if ( a && ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {
                sort = 1;
-               rc = sort_vals( a );
+               rc = ordered_value_sort( a, 1 );
                if ( rc )
                        return rc;
        }
index 5f7199f4f159e3eab7d41f37beace0754d158f48..8d467949d5d16875caa2b7bb9c08715c24fafe09 100644 (file)
@@ -744,59 +744,37 @@ int slap_mods_check(
                                ml->sml_nvalues[nvals].bv_len = 0;
                        }
 
-                       if( nvals ) {
-                               /* check for duplicates */
-                               int             i, j;
+                       /* check for duplicates, but ignore Deletes.
+                        */
+                       if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
+                               int             i, j, rc, match;
                                MatchingRule *mr = ad->ad_type->sat_equality;
 
-                               /* check if the values we're adding already exist */
-                               if( mr == NULL || !mr->smr_match ) {
-                                       for ( i = 1; ml->sml_values[i].bv_val != NULL; i++ ) {
-                                               /* test asserted values against themselves */
-                                               for( j = 0; j < i; j++ ) {
-                                                       if ( bvmatch( &ml->sml_values[i],
-                                                               &ml->sml_values[j] ) )
-                                                       {
-                                                               /* 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 {
-                                       int rc;
-                                       int match;
-
-                                       for ( i = 1; ml->sml_values[i].bv_val != NULL; i++ ) {
-                                               /* test asserted values against themselves */
-                                               for( j = 0; j < i; j++ ) {
-                                                       rc = 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;
-                                                       }
+                               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;
                                                }
                                        }
                                }
index 6e7d7ec1c5b8e1e42f227d37253cf8a831bac9dd..956ccfb78f3ddb1a1333443c8d8b21f8fc78633c 100644 (file)
@@ -93,14 +93,14 @@ modify_add_values(
                        assert( a->a_vals[0].bv_val );
                        for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) {
                                if ( mod->sm_nvalues ) {
-                                       rc = value_match( &match, mod->sm_desc, mr,
+                                       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 = value_match( &match, mod->sm_desc, mr,
-                                               SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+                                       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 );
                                }
 
@@ -143,7 +143,12 @@ modify_add_values(
        }
 
        /* no - add them */
-       rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues );
+       if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
+               rc = ordered_value_add( e, mod->sm_desc, a,
+                       pmod.sm_values, pmod.sm_nvalues );
+       } else {
+               rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues );
+       }
 
        if ( a != NULL && permissive ) {
                ch_free( pmod.sm_values );
@@ -229,22 +234,18 @@ modify_delete_values(
 
                        if( mod->sm_nvalues ) {
                                assert( a->a_nvals );
-                               rc = (*mr->smr_match)( &match,
-                                       SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
+                               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_desc->ad_type->sat_syntax,
-                                       mr, &a->a_nvals[j],
-                                       &mod->sm_nvalues[i] );
+                                       &a->a_nvals[j], &mod->sm_nvalues[i], text );
                        } else {
 #if 0
                                assert( a->a_nvals == NULL );
 #endif
-                               rc = (*mr->smr_match)( &match,
-                                       SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
-                                       a->a_desc->ad_type->sat_syntax,
-                                       mr, &a->a_vals[j],
-                                       &mod->sm_values[i] );
+                               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 ) {
@@ -290,7 +291,7 @@ modify_delete_values(
        for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); k++ ) {
                /* skip dummies */
                if( a->a_vals[k].bv_val == &dummy ) {
-                       assert( a->a_nvals == NULL || a->a_nvals[k].bv_val == &dummy );
+                       assert( a->a_nvals[k].bv_val == &dummy );
                        continue;
                }
                if ( j != k ) {
@@ -317,6 +318,9 @@ modify_delete_values(
                                mod->sm_desc->ad_cname.bv_val );
                        rc = LDAP_NO_SUCH_ATTRIBUTE;
                }
+       } else if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
+       /* For an ordered attribute, renumber the value indices */
+               ordered_value_sort( a, 1 );
        }
 
 return_results:;
index b351386b06dcfe37ef1fdd6e7b1a1594e6325144..b9793329bb50a429ff5c429d830f1943228c22d4 100644 (file)
@@ -1421,6 +1421,30 @@ LDAP_SLAPD_F (int) value_find_ex LDAP_P((
        struct berval *value,
        void *ctx ));
 
+LDAP_SLAPD_F (int) ordered_value_add LDAP_P((
+       Entry *e,
+       AttributeDescription *ad,
+       Attribute *a,
+       BerVarray vals,
+       BerVarray nvals ));
+
+LDAP_SLAPD_F (int) ordered_value_match LDAP_P((
+       int *match,
+       AttributeDescription *ad,
+       MatchingRule *mr,
+       unsigned flags,
+       struct berval *v1,
+       struct berval *v2,
+       const char ** text ));
+
+LDAP_SLAPD_F (void) ordered_value_renumber LDAP_P((
+       Attribute *a,
+       int vals ));
+
+LDAP_SLAPD_F (int) ordered_value_sort LDAP_P((
+       Attribute *a,
+       int do_renumber ));
+
 LDAP_SLAPD_F (int) value_add LDAP_P((
        BerVarray *vals,
        BerVarray addvals ));
index ebec9e348174b90c23b9ce1af187296a4c6e2fbd..3f0927c29d96efd5e719255364470e7a6cd7142d 100644 (file)
@@ -256,3 +256,303 @@ int value_find_ex(
        slap_sl_free( nval.bv_val, ctx );
        return LDAP_NO_SUCH_ATTRIBUTE;
 }
+
+/* assign new indexes to an attribute's ordered values */
+void
+ordered_value_renumber( Attribute *a, int vals )
+{
+       char *ptr, ibuf[64];    /* many digits */
+       struct berval ibv, tmp, vtmp;
+       int i;
+
+       ibv.bv_val = ibuf;
+
+       for (i=0; i<vals; i++) {
+               ibv.bv_len = sprintf(ibv.bv_val, "{%d}", i);
+               vtmp = a->a_vals[i];
+               if ( vtmp.bv_val[0] == '{' ) {
+                       ptr = strchr(vtmp.bv_val, '}') + 1;
+                       vtmp.bv_len -= ptr - vtmp.bv_val;
+                       vtmp.bv_val = ptr;
+               }
+               tmp.bv_len = ibv.bv_len + vtmp.bv_len;
+               tmp.bv_val = ch_malloc( tmp.bv_len + 1 );
+               strcpy( tmp.bv_val, ibv.bv_val );
+               AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len );
+               tmp.bv_val[tmp.bv_len] = '\0';
+               ch_free( a->a_vals[i].bv_val );
+               a->a_vals[i] = tmp;
+
+               if ( a->a_nvals && a->a_nvals != a->a_vals ) {
+                       vtmp = a->a_nvals[i];
+                       if ( vtmp.bv_val[0] == '{' ) {
+                               ptr = strchr(vtmp.bv_val, '}') + 1;
+                               vtmp.bv_len -= ptr - vtmp.bv_val;
+                               vtmp.bv_val = ptr;
+                       }
+                       tmp.bv_len = ibv.bv_len + vtmp.bv_len;
+                       tmp.bv_val = ch_malloc( tmp.bv_len + 1 );
+                       strcpy( tmp.bv_val, ibv.bv_val );
+                       AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len );
+                       tmp.bv_val[tmp.bv_len] = '\0';
+                       ch_free( a->a_nvals[i].bv_val );
+                       a->a_nvals[i] = tmp;
+               }
+       }
+}
+
+/* Sort the values in an X-ORDERED VALUES attribute.
+ * If the values have no index, index them in their given order.
+ * If the values have indexes, sort them.
+ * If some are indexed and some are not, return Error.
+ */
+int
+ordered_value_sort( Attribute *a, int do_renumber )
+{
+       int i, vals;
+       int index = 0, noindex = 0, renumber = 0, gotnvals = 0;
+       struct berval tmp;
+       char *ptr;
+
+       if ( a->a_nvals && a->a_nvals != a->a_vals )
+               gotnvals = 1;
+
+       /* count attrs, look for index */
+       for (i=0; a->a_vals[i].bv_val; i++) {
+               if ( a->a_vals[i].bv_val[0] == '{' ) {
+                       char *ptr;
+                       index = 1;
+                       ptr = strchr( a->a_vals[i].bv_val, '}' );
+                       if ( !ptr || !ptr[1] )
+                               return LDAP_INVALID_SYNTAX;
+                       if ( noindex )
+                               return LDAP_INVALID_SYNTAX;
+               } else {
+                       noindex = 1;
+                       if ( index )
+                               return LDAP_INVALID_SYNTAX;
+               }
+       }
+       vals = i;
+
+       /* If values have indexes, sort the values */
+       if ( index ) {
+               int *indexes, j, idx;
+               struct berval ntmp;
+
+#if 0
+               /* Strip index from normalized values */
+               if ( !a->a_nvals || a->a_vals == a->a_nvals ) {
+                       a->a_nvals = ch_malloc( (vals+1)*sizeof(struct berval));
+                       BER_BVZERO(a->a_nvals+vals);
+                       for ( i=0; i<vals; i++ ) {
+                               ptr = strchr(a->a_vals[i].bv_val, '}') + 1;
+                               a->a_nvals[i].bv_len = a->a_vals[i].bv_len -
+                                       (ptr - a->a_vals[i].bv_val);
+                               a->a_nvals[i].bv_val = ch_malloc( a->a_nvals[i].bv_len + 1);
+                               strcpy(a->a_nvals[i].bv_val, ptr );
+                       }
+               } else {
+                       for ( i=0; i<vals; i++ ) {
+                               ptr = strchr(a->a_nvals[i].bv_val, '}') + 1;
+                               a->a_nvals[i].bv_len -= ptr - a->a_nvals[i].bv_val;
+                               strcpy(a->a_nvals[i].bv_val, ptr);
+                       }
+               }
+#endif
+                               
+               indexes = ch_malloc( vals * sizeof(int) );
+               for ( i=0; i<vals; i++)
+                       indexes[i] = strtol(a->a_vals[i].bv_val+1, NULL, 0);
+
+               /* Insertion sort */
+               for ( i=1; i<vals; i++ ) {
+                       idx = indexes[i];
+                       tmp = a->a_vals[i];
+                       if ( gotnvals ) ntmp = a->a_nvals[i];
+                       j = i;
+                       while ((j > 0) && (indexes[j-1] > idx)) {
+                               indexes[j] = indexes[j-1];
+                               a->a_vals[j] = a->a_vals[j-1];
+                               if ( gotnvals ) a->a_nvals[j] = a->a_nvals[j-1];
+                               j--;
+                       }
+                       indexes[j] = idx;
+                       a->a_vals[j] = tmp;
+                       if ( gotnvals ) a->a_nvals[j] = ntmp;
+               }
+
+               /* If range is not contiguous, must renumber */
+               if ( indexes[0] != 0 || indexes[vals-1] != vals-1 ) {
+                       renumber = 1;
+               }
+       } else {
+               renumber = 1;
+       }
+
+       if ( do_renumber && renumber )
+               ordered_value_renumber( a, vals );
+
+       return 0;
+}
+
+/* A wrapper for value match, handles Equality matches for attributes
+ * with ordered values.
+ */
+int
+ordered_value_match(
+       int *match,
+       AttributeDescription *ad,
+       MatchingRule *mr,
+       unsigned flags,
+       struct berval *v1, /* stored value */
+       struct berval *v2, /* assertion */
+       const char ** text )
+{
+       struct berval bv1, bv2;
+
+       /* X-ORDERED VALUES equality matching:
+        * If (SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX) that means we are
+        * comparing two attribute values. In this case, we want to ignore
+        * the ordering index of both values, we just want to know if their
+        * main values are equal.
+        *
+        * If (SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX) then we are comparing
+        * an assertion against an attribute value.
+        *    If the assertion has no index, the index of the value is ignored. 
+        *    If the assertion has only an index, the remainder of the value is
+        *      ignored.
+        *    If the assertion has index and value, both are compared.
+        */
+       if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) {
+               char *ptr;
+               struct berval iv;
+
+               bv1 = *v1;
+               bv2 = *v2;
+               iv = bv2;
+
+               /* Skip past the assertion index */
+               if ( bv2.bv_val[0] == '{' ) {
+                       ptr = strchr( bv2.bv_val, '}' ) + 1;
+                       bv2.bv_len -= ptr - bv2.bv_val;
+                       bv2.bv_val = ptr;
+                       v2 = &bv2;
+               }
+
+               if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( flags )) {
+                       if ( iv.bv_val[0] == '{' && bv1.bv_val[0] == '{' ) {
+                       /* compare index values first */
+                               long l1, l2, ret;
+
+                               l1 = strtol( bv1.bv_val+1, NULL, 0 );
+                               l2 = strtol( iv.bv_val+1, &ptr, 0 );
+
+                               ret = l1 - l2;
+
+                               /* If not equal, or we're only comparing the index,
+                                * return result now.
+                                */
+                               if ( ret || ptr == iv.bv_val + iv.bv_len ) {
+                                       *match = ( ret < 0 ) ? -1 : (ret > 0 );
+                                       return LDAP_SUCCESS;
+                               }
+                       }
+               }
+               /* Skip past the attribute index */
+               if ( bv1.bv_val[0] == '{' ) {
+                       ptr = strchr( bv1.bv_val, '}' ) + 1;
+                       bv1.bv_len -= ptr - bv1.bv_val;
+                       bv1.bv_val = ptr;
+                       v1 = &bv1;
+               }
+       }
+
+       if ( !mr || !mr->smr_match ) {
+               *match = ber_bvcmp( v1, v2 );
+               return LDAP_SUCCESS;
+       }
+
+       return value_match( match, ad, mr, flags, v1, v2, text );
+}
+
+int
+ordered_value_add(
+       Entry *e,
+       AttributeDescription *ad,
+       Attribute *a,
+       BerVarray vals,
+       BerVarray nvals
+)
+{
+       int i, j, k, anum, vnum;
+       BerVarray new, nnew = NULL;
+
+       /* count new vals */
+       for (i=0; !BER_BVISNULL( vals+i ); i++) ;
+       vnum = i;
+
+       if ( a ) {
+               for (i=0; !BER_BVISNULL( a->a_vals+i ); i++) ;
+               anum = i;
+               ordered_value_sort( a, 0 );
+       } else {
+               Attribute **ap;
+               anum = 0;
+               for ( ap=&e->e_attrs; *ap; ap = &(*ap)->a_next ) ;
+               a = ch_calloc( 1, sizeof(Attribute) );
+               a->a_desc = ad;
+               *ap = a;
+       }
+
+       new = ch_malloc( (anum+vnum+1) * sizeof(struct berval));
+       if ( a->a_nvals && a->a_nvals != a->a_vals ) {
+               nnew = ch_malloc( (anum+vnum+1) * sizeof(struct berval));
+               /* Shouldn't happen... */
+               if ( !nvals ) nvals = vals;
+       }
+       if ( anum ) {
+               AC_MEMCPY( new, a->a_vals, anum * sizeof(struct berval));
+               if ( nnew )
+                       AC_MEMCPY( nnew, a->a_nvals, anum * sizeof(struct berval));
+       }
+
+       for (i=0; i<vnum; i++) {
+               k = -1;
+               if ( vals[i].bv_val[0] == '{' ) {
+                       k = strtol( vals[i].bv_val+1, NULL, 0 );
+                       if ( k > anum ) k = -1;
+               }
+               /* No index, or index is greater than current number of
+                * values, just tack onto the end
+                */
+               if ( k < 0 ) {
+                       ber_dupbv( new+anum, vals+i );
+                       if ( nnew ) ber_dupbv( nnew+anum, nvals+i );
+
+               /* Indexed, push everything else down one and insert */
+               } else {
+                       for (j=anum; j>k; j--) {
+                               new[j] = new[j-1];
+                               if ( nnew ) nnew[j] = nnew[j-1];
+                       }
+                       ber_dupbv( new+k, vals+i );
+                       if ( nnew ) ber_dupbv( nnew+k, nvals+i );
+               }
+               anum++;
+       }
+       BER_BVZERO( new+anum );
+       ch_free( a->a_vals );
+       a->a_vals = new;
+       if ( nnew ) {
+               BER_BVZERO( nnew+anum );
+               ch_free( a->a_nvals );
+               a->a_nvals = nnew;
+       } else {
+               a->a_nvals = a->a_vals;
+       }
+
+       ordered_value_renumber( a, anum );
+
+       return 0;
+}