X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-mdb%2Fmodify.c;h=e0ca295904de856d85c1de72bd7a7f5021fd7c13;hb=8300eee0179798abe4a55cad6170044d1a80cf99;hp=35682cefe8845fc70feb065fac23c440b95be3c5;hpb=bd1068204dff009e381ea89c362ed82088fd2011;p=openldap diff --git a/servers/slapd/back-mdb/modify.c b/servers/slapd/back-mdb/modify.c index 35682cefe8..e0ca295904 100644 --- a/servers/slapd/back-mdb/modify.c +++ b/servers/slapd/back-mdb/modify.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2015 The OpenLDAP Foundation. + * Copyright 2000-2017 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,11 +49,20 @@ mdb_modify_idxflags( 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 { @@ -74,13 +83,17 @@ int mdb_modify_internal( 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); @@ -129,16 +142,69 @@ int mdb_modify_internal( 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; @@ -148,16 +214,59 @@ int mdb_modify_internal( 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; @@ -172,6 +281,36 @@ int mdb_modify_internal( 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; @@ -198,21 +337,9 @@ int mdb_modify_internal( * 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, @@ -222,23 +349,8 @@ int mdb_modify_internal( * 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 ) { @@ -254,17 +366,9 @@ int mdb_modify_internal( * 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", @@ -458,6 +562,7 @@ mdb_modify( Operation *op, SlapReply *rs ) 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 ); @@ -635,12 +740,15 @@ mdb_modify( Operation *op, SlapReply *rs ) 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; } } @@ -683,6 +791,7 @@ done: if( moi == &opinfo ) { if( txn != NULL ) { + mdb->mi_numads = numads; mdb_txn_abort( txn ); } if ( opinfo.moi_oe.oe_key ) {