Preliminary sorted value support

This commit is contained in:
Howard Chu 2007-09-24 01:31:23 +00:00
parent ebb9e029a7
commit e8c2414831
14 changed files with 560 additions and 305 deletions

View 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;

View 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;
}

View 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... */

View 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++ ) {

View 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 )

View 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;
}
}
/* Quicksort + Insertion sort for small arrays */
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
*/
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 */
ad = ml->sml_desc;
nvals = ml->sml_numvals;
cv = ml->sml_nvalues ? ml->sml_nvalues : ml->sml_values;
if ( ad == slap_schema.si_ad_objectClass )
mr = NULL; /* shortcut matching */
/* 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;
}
/* record indices to preserve input ordering */
ix = slap_sl_malloc( nvals * sizeof(int), ctx );
for (i=0; i<nvals; i++) ix[i] = i;
if ( ad == slap_schema.si_ad_objectClass )
mr = NULL; /* shortcut matching */
else
mr = ad->ad_type->sat_equality;
ir = nvals-1;
l = 0;
jstack = 0;
/* record indices to preserve input ordering */
ix = slap_sl_malloc( nvals * sizeof(int), ctx );
for (i=0; i<nvals; i++) ix[i] = i;
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;
}
}
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);
}
done:
if ( i >= 0 )
j = ix[i];
slap_sl_free( ix, ctx );
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;
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 );
}
#endif /* SLAP_MODS_CHECK_QUICKSORT */
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 )
*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;
}

View 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;
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;
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 );
}
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;
}
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;
}
/* Locate values to delete */
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 ) {
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;
}
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 ( match != 0 ) {
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;
}

View 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 ) );

View 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;
}

View 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;

View 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 );

View 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 {

View 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;

View 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];
}