} 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;
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,
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;
}
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 ] );
/* 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... */
CFG_HIDDEN,
CFG_MONITORING,
CFG_SERVERID,
+ CFG_SORTVALS,
CFG_LAST
};
{ "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 },
"NAME 'olcFrontendConfig' "
"DESC 'OpenLDAP frontend configuration' "
"AUXILIARY "
- "MAY ( olcDefaultSearchBase $ olcPasswordHash ) )",
+ "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )",
Cft_Database, NULL, NULL },
#ifdef SLAPD_MODULES
{ "( OLcfgGlOc:8 "
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;
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;
}
}
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 */
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;
*/
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;
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++ ) {
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;
} 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 )
/* 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;
}
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 ) {
}
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 ) {
* 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];
}
/* 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;
}
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
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 */
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++;
}
}
/* 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",
/* For an ordered attribute, renumber the value indices */
ordered_value_sort( a, 1 );
}
-
-return_results:;
-
+return_result:
+ if ( id2 )
+ ch_free( id2 );
return rc;
}
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 ) );
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 ) );
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 ] );
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 ];
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;
}
ber_memfree( ml->sml_nvalues[ i ].bv_val );
BER_BVZERO( &ml->sml_nvalues[ i ] );
}
+ ml->sml_numvals--;
if ( j - i == 1 ) {
break;
}
ber_memfree( ml->sml_nvalues[ i ].bv_val );
BER_BVZERO( &ml->sml_nvalues[ i ] );
}
+ ml->sml_numvals--;
if ( j - i == 1 ) {
break;
}
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;
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,
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 );
#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
/*
* 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
};
/*
* 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
*/
#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 {
int
bvptr2obj(
struct berval **bvptr,
- BerVarray *bvobj )
+ BerVarray *bvobj,
+ unsigned *num )
{
int rc = LDAP_SUCCESS;
int i;
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 ) {
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;
* 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;
}
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;
}
attr_delete( &e->e_attrs, ad );
- rc = bvptr2obj( vals, &bv );
+ rc = bvptr2obj( vals, &bv, NULL );
if ( rc != LDAP_SUCCESS ) {
return -1;
}
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 );
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;
}
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;
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;
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 );
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];
}
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];
}