Back to index

openldap  2.4.31
modify.cpp
Go to the documentation of this file.
00001 /* modify.cpp - ndb backend modify routine */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Howard Chu for inclusion
00018  * in OpenLDAP Software. This work was sponsored by MySQL.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/string.h>
00025 #include <ac/time.h>
00026 
00027 #include "back-ndb.h"
00028 
00029 /* This is a copy from slapd/mods.c, but with compaction tweaked
00030  * to swap values from the tail into deleted slots, to reduce the
00031  * overall update traffic.
00032  */
00033 static int
00034 ndb_modify_delete(
00035        Entry  *e,
00036        Modification  *mod,
00037        int    permissive,
00038        const char    **text,
00039        char *textbuf, size_t textlen,
00040        int *idx )
00041 {
00042        Attribute     *a;
00043        MatchingRule  *mr = mod->sm_desc->ad_type->sat_equality;
00044        struct berval *cvals;
00045        int           *id2 = NULL;
00046        int           i, j, rc = 0, num;
00047        unsigned flags;
00048        char          dummy = '\0';
00049 
00050        /* For ordered vals, we have no choice but to preserve order */
00051        if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )
00052               return modify_delete_vindex( e, mod, permissive, text,
00053                      textbuf, textlen, idx );
00054 
00055        /*
00056         * If permissive is set, then the non-existence of an 
00057         * attribute is not treated as an error.
00058         */
00059 
00060        /* delete the entire attribute */
00061        if ( mod->sm_values == NULL ) {
00062               rc = attr_delete( &e->e_attrs, mod->sm_desc );
00063 
00064               if( permissive ) {
00065                      rc = LDAP_SUCCESS;
00066               } else if( rc != LDAP_SUCCESS ) {
00067                      *text = textbuf;
00068                      snprintf( textbuf, textlen,
00069                             "modify/delete: %s: no such attribute",
00070                             mod->sm_desc->ad_cname.bv_val );
00071                      rc = LDAP_NO_SUCH_ATTRIBUTE;
00072               }
00073               return rc;
00074        }
00075 
00076        /* FIXME: Catch old code that doesn't set sm_numvals.
00077         */
00078        if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) {
00079               for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ );
00080               assert( mod->sm_numvals == i );
00081        }
00082        if ( !idx ) {
00083               id2 = (int *)ch_malloc( mod->sm_numvals * sizeof( int ));
00084               idx = id2;
00085        }
00086 
00087        if( mr == NULL || !mr->smr_match ) {
00088               /* disallow specific attributes from being deleted if
00089                      no equality rule */
00090               *text = textbuf;
00091               snprintf( textbuf, textlen,
00092                      "modify/delete: %s: no equality matching rule",
00093                      mod->sm_desc->ad_cname.bv_val );
00094               rc = LDAP_INAPPROPRIATE_MATCHING;
00095               goto return_result;
00096        }
00097 
00098        /* delete specific values - find the attribute first */
00099        if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
00100               if( permissive ) {
00101                      rc = LDAP_SUCCESS;
00102                      goto return_result;
00103               }
00104               *text = textbuf;
00105               snprintf( textbuf, textlen,
00106                      "modify/delete: %s: no such attribute",
00107                      mod->sm_desc->ad_cname.bv_val );
00108               rc = LDAP_NO_SUCH_ATTRIBUTE;
00109               goto return_result;
00110        }
00111 
00112        if ( mod->sm_nvalues ) {
00113               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
00114                      | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
00115                      | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH;
00116               cvals = mod->sm_nvalues;
00117        } else {
00118               flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX;
00119               cvals = mod->sm_values;
00120        }
00121 
00122        /* Locate values to delete */
00123        for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
00124               unsigned sort;
00125               rc = attr_valfind( a, flags, &cvals[i], &sort, NULL );
00126               if ( rc == LDAP_SUCCESS ) {
00127                      idx[i] = sort;
00128               } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
00129                      if ( permissive ) {
00130                             idx[i] = -1;
00131                             continue;
00132                      }
00133                      *text = textbuf;
00134                      snprintf( textbuf, textlen,
00135                             "modify/delete: %s: no such value",
00136                             mod->sm_desc->ad_cname.bv_val );
00137                      goto return_result;
00138               } else {
00139                      *text = textbuf;
00140                      snprintf( textbuf, textlen,
00141                             "modify/delete: %s: matching rule failed",
00142                             mod->sm_desc->ad_cname.bv_val );
00143                      goto return_result;
00144               }
00145        }
00146 
00147        num = a->a_numvals;
00148 
00149        /* Delete the values */
00150        for ( i = 0; i < mod->sm_numvals; i++ ) {
00151               /* Skip permissive values that weren't found */
00152               if ( idx[i] < 0 )
00153                      continue;
00154               /* Skip duplicate delete specs */
00155               if ( a->a_vals[idx[i]].bv_val == &dummy )
00156                      continue;
00157               /* delete value and mark it as gone */
00158               free( a->a_vals[idx[i]].bv_val );
00159               a->a_vals[idx[i]].bv_val = &dummy;
00160               if( a->a_nvals != a->a_vals ) {
00161                      free( a->a_nvals[idx[i]].bv_val );
00162                      a->a_nvals[idx[i]].bv_val = &dummy;
00163               }
00164               a->a_numvals--;
00165        }
00166 
00167        /* compact array */
00168        for ( i=0; i<num; i++ ) {
00169               if ( a->a_vals[i].bv_val != &dummy )
00170                      continue;
00171               for ( --num; num > i && a->a_vals[num].bv_val == &dummy; num-- )
00172                      ;
00173               a->a_vals[i] = a->a_vals[num];
00174               if ( a->a_nvals != a->a_vals )
00175                      a->a_nvals[i] = a->a_nvals[num];
00176        }
00177 
00178        BER_BVZERO( &a->a_vals[num] );
00179        if (a->a_nvals != a->a_vals) {
00180               BER_BVZERO( &a->a_nvals[num] );
00181        }
00182 
00183        /* if no values remain, delete the entire attribute */
00184        if ( !a->a_numvals ) {
00185               if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
00186                      /* Can never happen */
00187                      *text = textbuf;
00188                      snprintf( textbuf, textlen,
00189                             "modify/delete: %s: no such attribute",
00190                             mod->sm_desc->ad_cname.bv_val );
00191                      rc = LDAP_NO_SUCH_ATTRIBUTE;
00192               }
00193        }
00194 return_result:
00195        if ( id2 )
00196               ch_free( id2 );
00197        return rc;
00198 }
00199 
00200 int ndb_modify_internal(
00201        Operation *op,
00202        NdbArgs *NA,
00203        const char **text,
00204        char *textbuf,
00205        size_t textlen )
00206 {
00207        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
00208        Modification  *mod;
00209        Modifications *ml;
00210        Modifications *modlist = op->orm_modlist;
00211        NdbAttrInfo **modai, *atmp;
00212        const NdbDictionary::Dictionary *myDict;
00213        const NdbDictionary::Table *myTable;
00214        int got_oc = 0, nmods = 0, nai = 0, i, j;
00215        int rc, indexed = 0;
00216        Attribute *old = NULL;
00217 
00218        Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n",
00219               NA->e->e_id, NA->e->e_dn, 0);
00220 
00221        if ( !acl_check_modlist( op, NA->e, modlist )) {
00222               return LDAP_INSUFFICIENT_ACCESS;
00223        }
00224 
00225        old = attrs_dup( NA->e->e_attrs );
00226 
00227        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
00228               mod = &ml->sml_mod;
00229               nmods++;
00230 
00231               switch ( mod->sm_op ) {
00232               case LDAP_MOD_ADD:
00233                      Debug(LDAP_DEBUG_ARGS,
00234                             "ndb_modify_internal: add %s\n",
00235                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00236                      rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
00237                             text, textbuf, textlen );
00238                      if( rc != LDAP_SUCCESS ) {
00239                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00240                                    rc, *text, 0);
00241                      }
00242                      break;
00243 
00244               case LDAP_MOD_DELETE:
00245                      Debug(LDAP_DEBUG_ARGS,
00246                             "ndb_modify_internal: delete %s\n",
00247                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00248                      rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op),
00249                             text, textbuf, textlen, NULL );
00250                      assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
00251                      if( rc != LDAP_SUCCESS ) {
00252                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00253                                    rc, *text, 0);
00254                      }
00255                      break;
00256 
00257               case LDAP_MOD_REPLACE:
00258                      Debug(LDAP_DEBUG_ARGS,
00259                             "ndb_modify_internal: replace %s\n",
00260                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00261                      rc = modify_replace_values( NA->e, mod, get_permissiveModify(op),
00262                             text, textbuf, textlen );
00263                      if( rc != LDAP_SUCCESS ) {
00264                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00265                                    rc, *text, 0);
00266                      }
00267                      break;
00268 
00269               case LDAP_MOD_INCREMENT:
00270                      Debug(LDAP_DEBUG_ARGS,
00271                             "ndb_modify_internal: increment %s\n",
00272                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00273                      rc = modify_increment_values( NA->e, mod, get_permissiveModify(op),
00274                             text, textbuf, textlen );
00275                      if( rc != LDAP_SUCCESS ) {
00276                             Debug(LDAP_DEBUG_ARGS,
00277                                    "ndb_modify_internal: %d %s\n",
00278                                    rc, *text, 0);
00279                      }
00280                      break;
00281 
00282               case SLAP_MOD_SOFTADD:
00283                      Debug(LDAP_DEBUG_ARGS,
00284                             "ndb_modify_internal: softadd %s\n",
00285                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00286                      mod->sm_op = LDAP_MOD_ADD;
00287 
00288                      rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
00289                             text, textbuf, textlen );
00290 
00291                      mod->sm_op = SLAP_MOD_SOFTADD;
00292 
00293                      if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
00294                             rc = LDAP_SUCCESS;
00295                      }
00296 
00297                      if( rc != LDAP_SUCCESS ) {
00298                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00299                                    rc, *text, 0);
00300                      }
00301                      break;
00302 
00303               case SLAP_MOD_SOFTDEL:
00304                      Debug(LDAP_DEBUG_ARGS,
00305                             "ndb_modify_internal: softdel %s\n",
00306                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00307                      mod->sm_op = LDAP_MOD_DELETE;
00308 
00309                      rc = modify_delete_values( NA->e, mod, get_permissiveModify(op),
00310                             text, textbuf, textlen );
00311 
00312                      mod->sm_op = SLAP_MOD_SOFTDEL;
00313 
00314                      if ( rc == LDAP_NO_SUCH_ATTRIBUTE) {
00315                             rc = LDAP_SUCCESS;
00316                      }
00317 
00318                      if( rc != LDAP_SUCCESS ) {
00319                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00320                                    rc, *text, 0);
00321                      }
00322                      break;
00323 
00324               case SLAP_MOD_ADD_IF_NOT_PRESENT:
00325                      Debug(LDAP_DEBUG_ARGS,
00326                             "ndb_modify_internal: add_if_not_present %s\n",
00327                             mod->sm_desc->ad_cname.bv_val, 0, 0);
00328                      if ( attr_find( NA->e->e_attrs, mod->sm_desc ) ) {
00329                             rc = LDAP_SUCCESS;
00330                             break;
00331                      }
00332 
00333                      mod->sm_op = LDAP_MOD_ADD;
00334 
00335                      rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
00336                             text, textbuf, textlen );
00337 
00338                      mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
00339 
00340                      if( rc != LDAP_SUCCESS ) {
00341                             Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00342                                    rc, *text, 0);
00343                      }
00344                      break;
00345 
00346               default:
00347                      Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n",
00348                             mod->sm_op, 0, 0);
00349                      *text = "Invalid modify operation";
00350                      rc = LDAP_OTHER;
00351                      Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
00352                             rc, *text, 0);
00353               }
00354 
00355               if ( rc != LDAP_SUCCESS ) {
00356                      attrs_free( old );
00357                      return rc; 
00358               }
00359 
00360               /* If objectClass was modified, reset the flags */
00361               if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
00362                      NA->e->e_ocflags = 0;
00363                      got_oc = 1;
00364               }
00365        }
00366 
00367        /* check that the entry still obeys the schema */
00368        rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL,
00369               text, textbuf, textlen );
00370        if ( rc != LDAP_SUCCESS || op->o_noop ) {
00371               if ( rc != LDAP_SUCCESS ) {
00372                      Debug( LDAP_DEBUG_ANY,
00373                             "entry failed schema check: %s\n",
00374                             *text, 0, 0 );
00375               }
00376               attrs_free( old );
00377               return rc;
00378        }
00379 
00380        if ( got_oc ) {
00381               rc = ndb_entry_put_info( op->o_bd, NA, 1 );
00382               if ( rc ) {
00383                      attrs_free( old );
00384                      return rc;
00385               }
00386        }
00387 
00388        /* apply modifications to DB */
00389        modai = (NdbAttrInfo **)op->o_tmpalloc( nmods * sizeof(NdbAttrInfo*), op->o_tmpmemctx );
00390 
00391        /* Get the unique list of modified attributes */
00392        ldap_pvt_thread_rdwr_rlock( &ni->ni_ai_rwlock );
00393        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
00394               /* Already took care of objectclass */
00395               if ( ml->sml_desc == slap_schema.si_ad_objectClass )
00396                      continue;
00397               for ( i=0; i<nai; i++ ) {
00398                      if ( ml->sml_desc->ad_type == modai[i]->na_attr )
00399                             break;
00400               }
00401               /* This attr was already updated */
00402               if ( i < nai )
00403                      continue;
00404               modai[nai] = ndb_ai_find( ni, ml->sml_desc->ad_type );
00405               if ( modai[nai]->na_flag & NDB_INFO_INDEX )
00406                      indexed++;
00407               nai++;
00408        }
00409        ldap_pvt_thread_rdwr_runlock( &ni->ni_ai_rwlock );
00410 
00411        /* If got_oc, this was already done above */
00412        if ( indexed && !got_oc) {
00413               rc = ndb_entry_put_info( op->o_bd, NA, 1 );
00414               if ( rc ) {
00415                      attrs_free( old );
00416                      return rc;
00417               }
00418        }
00419 
00420        myDict = NA->ndb->getDictionary();
00421 
00422        /* sort modai so that OcInfo's are contiguous */
00423        {
00424               int j, k;
00425               for ( i=0; i<nai; i++ ) {
00426                      for ( j=i+1; j<nai; j++ ) {
00427                             if ( modai[i]->na_oi == modai[j]->na_oi )
00428                                    continue;
00429                             for ( k=j+1; k<nai; k++ ) {
00430                                    if ( modai[i]->na_oi == modai[k]->na_oi ) {
00431                                           atmp = modai[j];
00432                                           modai[j] = modai[k];
00433                                           modai[k] = atmp;
00434                                           break;
00435                                    }
00436                             }
00437                             /* there are no more na_oi's that match modai[i] */
00438                             if ( k == nai ) {
00439                                    i = j;
00440                             }
00441                      }
00442               }
00443        }
00444 
00445        /* One call per table... */
00446        for ( i=0; i<nai; i += j ) {
00447               atmp = modai[i];
00448               for ( j=i+1; j<nai; j++ )
00449                      if ( atmp->na_oi != modai[j]->na_oi )
00450                             break;
00451               j -= i;
00452               myTable = myDict->getTable( atmp->na_oi->no_table.bv_val );
00453               if ( !myTable )
00454                      continue;
00455               rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old );
00456               if ( rc ) break;
00457        }
00458        attrs_free( old );
00459        return rc;
00460 }
00461 
00462 
00463 int
00464 ndb_back_modify( Operation *op, SlapReply *rs )
00465 {
00466        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
00467        Entry         e = {0};
00468        int           manageDSAit = get_manageDSAit( op );
00469        char textbuf[SLAP_TEXT_BUFLEN];
00470        size_t textlen = sizeof textbuf;
00471 
00472        int           num_retries = 0;
00473 
00474        NdbArgs NA;
00475        NdbRdns rdns;
00476        struct berval matched;
00477 
00478        LDAPControl **preread_ctrl = NULL;
00479        LDAPControl **postread_ctrl = NULL;
00480        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00481        int num_ctrls = 0;
00482 
00483        Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(ndb_back_modify) ": %s\n",
00484               op->o_req_dn.bv_val, 0, 0 );
00485 
00486        ctrls[num_ctrls] = NULL;
00487 
00488        slap_mods_opattrs( op, &op->orm_modlist, 1 );
00489 
00490        e.e_name = op->o_req_dn;
00491        e.e_nname = op->o_req_ndn;
00492 
00493        /* Get our NDB handle */
00494        rs->sr_err = ndb_thread_handle( op, &NA.ndb );
00495        rdns.nr_num = 0;
00496        NA.rdns = &rdns;
00497        NA.e = &e;
00498 
00499        if( 0 ) {
00500 retry: /* transaction retry */
00501               NA.txn->close();
00502               NA.txn = NULL;
00503               if( e.e_attrs ) {
00504                      attrs_free( e.e_attrs );
00505                      e.e_attrs = NULL;
00506               }
00507               Debug(LDAP_DEBUG_TRACE,
00508                      LDAP_XSTRING(ndb_back_modify) ": retrying...\n", 0, 0, 0);
00509               if ( op->o_abandon ) {
00510                      rs->sr_err = SLAPD_ABANDON;
00511                      goto return_results;
00512               }
00513               if ( NA.ocs ) {
00514                      ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
00515               }
00516               ndb_trans_backoff( ++num_retries );
00517        }
00518        NA.ocs = NULL;
00519 
00520        /* begin transaction */
00521        NA.txn = NA.ndb->startTransaction();
00522        rs->sr_text = NULL;
00523        if( !NA.txn ) {
00524               Debug( LDAP_DEBUG_TRACE,
00525                      LDAP_XSTRING(ndb_back_modify) ": startTransaction failed: %s (%d)\n",
00526                      NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
00527               rs->sr_err = LDAP_OTHER;
00528               rs->sr_text = "internal error";
00529               goto return_results;
00530        }
00531 
00532        /* get entry or ancestor */
00533        rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
00534        switch( rs->sr_err ) {
00535        case 0:
00536               break;
00537        case LDAP_NO_SUCH_OBJECT:
00538               Debug( LDAP_DEBUG_ARGS,
00539                      "<=- ndb_back_modify: no such object %s\n",
00540                      op->o_req_dn.bv_val, 0, 0 );
00541               rs->sr_matched = matched.bv_val;
00542               if (NA.ocs )
00543                      ndb_check_referral( op, rs, &NA );
00544               goto return_results;
00545 #if 0
00546        case DB_LOCK_DEADLOCK:
00547        case DB_LOCK_NOTGRANTED:
00548               goto retry;
00549 #endif
00550        case LDAP_BUSY:
00551               rs->sr_text = "ldap server busy";
00552               goto return_results;
00553        default:
00554               rs->sr_err = LDAP_OTHER;
00555               rs->sr_text = "internal error";
00556               goto return_results;
00557        }
00558 
00559        /* acquire and lock entry */
00560        rs->sr_err = ndb_entry_get_data( op, &NA, 1 );
00561 
00562        if ( !manageDSAit && is_entry_referral( &e ) ) {
00563               /* entry is a referral, don't allow modify */
00564               rs->sr_ref = get_entry_referrals( op, &e );
00565 
00566               Debug( LDAP_DEBUG_TRACE,
00567                      LDAP_XSTRING(ndb_back_modify) ": entry is referral\n",
00568                      0, 0, 0 );
00569 
00570               rs->sr_err = LDAP_REFERRAL;
00571               rs->sr_matched = e.e_name.bv_val;
00572               rs->sr_flags = REP_REF_MUSTBEFREED;
00573               goto return_results;
00574        }
00575 
00576        if ( get_assert( op ) &&
00577               ( test_filter( op, &e, (Filter*)get_assertion( op )) != LDAP_COMPARE_TRUE ))
00578        {
00579               rs->sr_err = LDAP_ASSERTION_FAILED;
00580               goto return_results;
00581        }
00582 
00583        if( op->o_preread ) {
00584               if( preread_ctrl == NULL ) {
00585                      preread_ctrl = &ctrls[num_ctrls++];
00586                      ctrls[num_ctrls] = NULL;
00587               }
00588               if ( slap_read_controls( op, rs, &e,
00589                      &slap_pre_read_bv, preread_ctrl ) )
00590               {
00591                      Debug( LDAP_DEBUG_TRACE,
00592                             "<=- " LDAP_XSTRING(ndb_back_modify) ": pre-read "
00593                             "failed!\n", 0, 0, 0 );
00594                      if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
00595                             /* FIXME: is it correct to abort
00596                              * operation if control fails? */
00597                             goto return_results;
00598                      }
00599               }
00600        }
00601 
00602        /* Modify the entry */
00603        rs->sr_err = ndb_modify_internal( op, &NA, &rs->sr_text, textbuf, textlen );
00604 
00605        if( rs->sr_err != LDAP_SUCCESS ) {
00606               Debug( LDAP_DEBUG_TRACE,
00607                      LDAP_XSTRING(ndb_back_modify) ": modify failed (%d)\n",
00608                      rs->sr_err, 0, 0 );
00609 #if 0
00610               switch( rs->sr_err ) {
00611               case DB_LOCK_DEADLOCK:
00612               case DB_LOCK_NOTGRANTED:
00613                      goto retry;
00614               }
00615 #endif
00616               goto return_results;
00617        }
00618 
00619        if( op->o_postread ) {
00620               if( postread_ctrl == NULL ) {
00621                      postread_ctrl = &ctrls[num_ctrls++];
00622                      ctrls[num_ctrls] = NULL;
00623               }
00624               if( slap_read_controls( op, rs, &e,
00625                      &slap_post_read_bv, postread_ctrl ) )
00626               {
00627                      Debug( LDAP_DEBUG_TRACE,
00628                             "<=- " LDAP_XSTRING(ndb_back_modify)
00629                             ": post-read failed!\n", 0, 0, 0 );
00630                      if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
00631                             /* FIXME: is it correct to abort
00632                              * operation if control fails? */
00633                             goto return_results;
00634                      }
00635               }
00636        }
00637 
00638        if( op->o_noop ) {
00639               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
00640                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00641                      rs->sr_text = "txn_abort (no-op) failed";
00642               } else {
00643                      rs->sr_err = LDAP_X_NO_OPERATION;
00644               }
00645        } else {
00646               if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
00647                      NdbOperation::AbortOnError, 1 )) != 0 ) {
00648                      rs->sr_text = "txn_commit failed";
00649               } else {
00650                      rs->sr_err = LDAP_SUCCESS;
00651               }
00652        }
00653 
00654        if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
00655               Debug( LDAP_DEBUG_TRACE,
00656                      LDAP_XSTRING(ndb_back_modify) ": txn_%s failed: %s (%d)\n",
00657                      op->o_noop ? "abort (no-op)" : "commit",
00658                      NA.txn->getNdbError().message, NA.txn->getNdbError().code );
00659               rs->sr_err = LDAP_OTHER;
00660               goto return_results;
00661        }
00662        NA.txn->close();
00663        NA.txn = NULL;
00664 
00665        Debug( LDAP_DEBUG_TRACE,
00666               LDAP_XSTRING(ndb_back_modify) ": updated%s id=%08lx dn=\"%s\"\n",
00667               op->o_noop ? " (no-op)" : "",
00668               e.e_id, op->o_req_dn.bv_val );
00669 
00670        rs->sr_err = LDAP_SUCCESS;
00671        rs->sr_text = NULL;
00672        if( num_ctrls ) rs->sr_ctrls = ctrls;
00673 
00674 return_results:
00675        if ( NA.ocs ) {
00676               ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
00677               NA.ocs = NULL;
00678        }
00679 
00680        if ( e.e_attrs != NULL ) {
00681               attrs_free( e.e_attrs );
00682               e.e_attrs = NULL;
00683        }
00684 
00685        if( NA.txn != NULL ) {
00686               NA.txn->execute( Rollback );
00687               NA.txn->close();
00688        }
00689 
00690        send_ldap_result( op, rs );
00691        slap_graduate_commit_csn( op );
00692 
00693        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
00694               slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00695               slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
00696        }
00697        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
00698               slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00699               slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
00700        }
00701 
00702        rs->sr_text = NULL;
00703        return rs->sr_err;
00704 }