/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2000-2015 The OpenLDAP Foundation.
+ * Copyright 2000-2018 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
ap = attr_find( oldattrs, desc );
if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
- /* Find all other attrs that index to same slot */
- for ( ap = newattrs; ap; ap = ap->a_next ) {
- ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
- if ( ai && ix2.bv_val == ix_at.bv_val )
- ap->a_flags |= SLAP_ATTR_IXADD;
+ /* ITS#8678 FIXME
+ * If using 32bit hashes, or substring index, must account for
+ * possible index collisions. If no substring index, and using
+ * 64bit hashes, assume we don't need to check for collisions.
+ *
+ * In 2.5 use refcounts and avoid all of this mess.
+ */
+ if (!slap_hash64(-1) || (ai->ai_indexmask & SLAP_INDEX_SUBSTR)) {
+ /* Find all other attrs that index to same slot */
+ for ( ap = newattrs; ap; ap = ap->a_next ) {
+ ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
+ if ( ai && ix2.bv_val == ix_at.bv_val )
+ ap->a_flags |= SLAP_ATTR_IXADD;
+ }
}
} else {
char *textbuf,
size_t textlen )
{
+ struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
int rc, err;
Modification *mod;
Modifications *ml;
Attribute *save_attrs;
- Attribute *ap;
+ Attribute *ap, *aold, *anew;
int glue_attr_delete = 0;
+ int softop, chkpresent;
int got_delete;
+ int a_flags;
+ MDB_cursor *mvc = NULL;
Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n",
e->e_id, e->e_dn, 0);
mod = &ml->sml_mod;
got_delete = 0;
+ aold = attr_find( e->e_attrs, mod->sm_desc );
+ if (aold)
+ a_flags = aold->a_flags;
+ else
+ a_flags = 0;
+
switch ( mod->sm_op ) {
case LDAP_MOD_ADD:
+ softop = 0;
+ chkpresent = 0;
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: add %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
+
+do_add:
err = modify_add_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
+
+ if( softop ) {
+ mod->sm_op = SLAP_MOD_SOFTADD;
+ if ( err == LDAP_TYPE_OR_VALUE_EXISTS )
+ err = LDAP_SUCCESS;
+ }
+ if( chkpresent ) {
+ mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
+ }
+
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
+ } else {
+ if (!aold)
+ anew = attr_find( e->e_attrs, mod->sm_desc );
+ else
+ anew = aold;
+ /* check for big multivalued attrs */
+ if ( anew->a_numvals > mdb->mi_multi_hi )
+ anew->a_flags |= SLAP_ATTR_BIG_MULTI;
+ if ( anew->a_flags & SLAP_ATTR_BIG_MULTI ) {
+ if (!mvc) {
+ err = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
+ if (err) {
+mval_fail: strncpy( textbuf, mdb_strerror( err ), textlen );
+ err = LDAP_OTHER;
+ break;
+ }
+ }
+ /* if prev was set, just add new values */
+ if (a_flags & SLAP_ATTR_BIG_MULTI ) {
+ anew = (Attribute *)mod;
+ /* Tweak nvals */
+ if (!anew->a_nvals)
+ anew->a_nvals = anew->a_vals;
+ }
+ err = mdb_mval_put(op, mvc, e->e_id, anew);
+ if (a_flags & SLAP_ATTR_BIG_MULTI ) {
+ /* Undo nvals tweak */
+ if (anew->a_nvals == anew->a_vals)
+ anew->a_nvals = NULL;
+ }
+ if ( err )
+ goto mval_fail;
+ }
}
break;
break;
}
+ softop = 0;
Debug(LDAP_DEBUG_ARGS,
"mdb_modify_internal: delete %s\n",
mod->sm_desc->ad_cname.bv_val, 0, 0);
+do_del:
err = modify_delete_values( e, mod, get_permissiveModify(op),
text, textbuf, textlen );
+
+ if (softop) {
+ mod->sm_op = SLAP_MOD_SOFTDEL;
+ if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
+ err = LDAP_SUCCESS;
+ softop = 2;
+ }
+ }
+
if( err != LDAP_SUCCESS ) {
Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
err, *text, 0);
} else {
- got_delete = 1;
+ if (softop != 2)
+ got_delete = 1;
+ /* check for big multivalued attrs */
+ if (a_flags & SLAP_ATTR_BIG_MULTI) {
+ Attribute a_dummy;
+ if (!mvc) {
+ err = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
+ if (err)
+ goto mval_fail;
+ }
+ if ( mod->sm_numvals ) {
+ anew = attr_find( e->e_attrs, mod->sm_desc );
+ if ( anew ) {
+ if ( anew->a_numvals < mdb->mi_multi_lo ) {
+ anew->a_flags ^= SLAP_ATTR_BIG_MULTI;
+ anew = NULL;
+ } else {
+ anew = (Attribute *)mod;
+ }
+ }
+ } else {
+ anew = NULL;
+ }
+ if (!anew) {
+ /* delete all values */
+ anew = &a_dummy;
+ anew->a_desc = mod->sm_desc;
+ anew->a_numvals = 0;
+ }
+ err = mdb_mval_del( op, mvc, e->e_id, anew );
+ if ( err )
+ goto mval_fail;
+ }
}
break;
err, *text, 0);
} else {
got_delete = 1;
+ if (a_flags & SLAP_ATTR_BIG_MULTI) {
+ Attribute a_dummy;
+ if (!mvc) {
+ err = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
+ if (err)
+ goto mval_fail;
+ }
+ /* delete all values */
+ anew = &a_dummy;
+ anew->a_desc = mod->sm_desc;
+ anew->a_numvals = 0;
+ err = mdb_mval_del( op, mvc, e->e_id, anew );
+ if (err)
+ goto mval_fail;
+ }
+ anew = attr_find( e->e_attrs, mod->sm_desc );
+ if (mod->sm_numvals > mdb->mi_multi_hi) {
+ anew->a_flags |= SLAP_ATTR_BIG_MULTI;
+ if (!mvc) {
+ err = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
+ if (err)
+ goto mval_fail;
+ }
+ err = mdb_mval_put(op, mvc, e->e_id, anew);
+ if (err)
+ goto mval_fail;
+ } else if (anew) {
+ /* revert back to normal attr */
+ anew->a_flags &= ~SLAP_ATTR_BIG_MULTI;
+ }
}
break;
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_ADD;
-
- err = modify_add_values( e, mod, get_permissiveModify(op),
- text, textbuf, textlen );
-
- mod->sm_op = SLAP_MOD_SOFTADD;
-
- if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
- err = LDAP_SUCCESS;
- }
-
- if( err != LDAP_SUCCESS ) {
- Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
- err, *text, 0);
- }
- break;
+ softop = 1;
+ chkpresent = 0;
+ goto do_add;
case SLAP_MOD_SOFTDEL:
Debug(LDAP_DEBUG_ARGS,
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_DELETE;
-
- err = modify_delete_values( e, mod, get_permissiveModify(op),
- text, textbuf, textlen );
-
- mod->sm_op = SLAP_MOD_SOFTDEL;
-
- if ( err == LDAP_SUCCESS ) {
- got_delete = 1;
- } else if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
- err = LDAP_SUCCESS;
- }
-
- if( err != LDAP_SUCCESS ) {
- Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
- err, *text, 0);
- }
- break;
+ softop = 1;
+ goto do_del;
case SLAP_MOD_ADD_IF_NOT_PRESENT:
if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) {
* We need to add index if necessary.
*/
mod->sm_op = LDAP_MOD_ADD;
-
- err = modify_add_values( e, mod, get_permissiveModify(op),
- text, textbuf, textlen );
-
- mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
-
- if( err != LDAP_SUCCESS ) {
- Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
- err, *text, 0);
- }
- break;
+ softop = 0;
+ chkpresent = 1;
+ goto do_add;
default:
Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n",
LDAPControl **postread_ctrl = NULL;
LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
int num_ctrls = 0;
+ int numads = mdb->mi_numads;
Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(mdb_modify) ": %s\n",
op->o_req_dn.bv_val, 0, 0 );
LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
opinfo.moi_oe.oe_key = NULL;
if( op->o_noop ) {
+ mdb->mi_numads = numads;
mdb_txn_abort( txn );
rs->sr_err = LDAP_X_NO_OPERATION;
txn = NULL;
goto return_results;
} else {
rs->sr_err = mdb_txn_commit( txn );
+ if ( rs->sr_err )
+ mdb->mi_numads = numads;
txn = NULL;
}
}
if( moi == &opinfo ) {
if( txn != NULL ) {
+ mdb->mi_numads = numads;
mdb_txn_abort( txn );
}
if ( opinfo.moi_oe.oe_key ) {