]> git.sur5r.net Git - openldap/blob - servers/slapd/back-wt/modify.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[openldap] / servers / slapd / back-wt / modify.c
1 /* OpenLDAP WiredTiger backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2002-2015 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
18  * based on back-bdb for inclusion in OpenLDAP Software.
19  * WiredTiger is a product of MongoDB Inc.
20  */
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include "back-wt.h"
25 #include "config.h"
26
27 static struct berval scbva[] = {
28         BER_BVC("glue"),
29         BER_BVNULL
30 };
31
32 static void
33 wt_modify_idxflags(
34         Operation *op,
35         AttributeDescription *desc,
36         int got_delete,
37         Attribute *newattrs,
38         Attribute *oldattrs )
39 {
40         struct berval   ix_at;
41         AttrInfo        *ai;
42
43         /* check if modified attribute was indexed
44          * but not in case of NOOP... */
45         ai = wt_index_mask( op->o_bd, desc, &ix_at );
46         if ( ai ) {
47                 if ( got_delete ) {
48                         Attribute       *ap;
49                         struct berval   ix2;
50
51                         ap = attr_find( oldattrs, desc );
52                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
53
54                         /* Find all other attrs that index to same slot */
55                         for ( ap = newattrs; ap; ap = ap->a_next ) {
56                                 ai = wt_index_mask( op->o_bd, ap->a_desc, &ix2 );
57                                 if ( ai && ix2.bv_val == ix_at.bv_val )
58                                         ap->a_flags |= SLAP_ATTR_IXADD;
59                         }
60
61                 } else {
62                         Attribute       *ap;
63
64                         ap = attr_find( newattrs, desc );
65                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
66                 }
67         }
68 }
69
70 int wt_modify_internal(
71         Operation *op,
72         wt_ctx *wc,
73         Modifications *modlist,
74         Entry *e,
75         const char **text,
76         char *textbuf,
77         size_t textlen )
78 {
79         int rc, err;
80         Modification    *mod;
81         Modifications   *ml;
82         Attribute       *save_attrs;
83         Attribute       *ap;
84         int                     glue_attr_delete = 0;
85         int                     got_delete;
86
87         Debug( LDAP_DEBUG_TRACE, "wt_modify_internal: 0x%08lx: %s\n",
88                    e->e_id, e->e_dn, 0);
89
90         if ( !acl_check_modlist( op, e, modlist )) {
91                 return LDAP_INSUFFICIENT_ACCESS;
92         }
93
94         /* save_attrs will be disposed of by caller */
95         save_attrs = e->e_attrs;
96         e->e_attrs = attrs_dup( e->e_attrs );
97
98         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
99                 int match;
100                 mod = &ml->sml_mod;
101                 switch( mod->sm_op ) {
102                 case LDAP_MOD_ADD:
103                 case LDAP_MOD_REPLACE:
104                         if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
105                                 value_match( &match, slap_schema.si_ad_structuralObjectClass,
106                                         slap_schema.si_ad_structuralObjectClass->
107                                                 ad_type->sat_equality,
108                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
109                                         &mod->sm_values[0], &scbva[0], text );
110                                 if ( !match ) glue_attr_delete = 1;
111                         }
112                 }
113                 if ( glue_attr_delete )
114                         break;
115         }
116
117         if ( glue_attr_delete ) {
118                 Attribute       **app = &e->e_attrs;
119                 while ( *app != NULL ) {
120                         if ( !is_at_operational( (*app)->a_desc->ad_type )) {
121                                 Attribute *save = *app;
122                                 *app = (*app)->a_next;
123                                 attr_free( save );
124                                 continue;
125                         }
126                         app = &(*app)->a_next;
127                 }
128         }
129
130         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
131                 mod = &ml->sml_mod;
132                 got_delete = 0;
133
134                 switch ( mod->sm_op ) {
135                 case LDAP_MOD_ADD:
136                         Debug(LDAP_DEBUG_ARGS,
137                                   "wt_modify_internal: add %s\n",
138                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
139                         err = modify_add_values( e, mod, get_permissiveModify(op),
140                                                                          text, textbuf, textlen );
141                         if( err != LDAP_SUCCESS ) {
142                                 Debug(LDAP_DEBUG_ARGS, "wt_modify_internal: %d %s\n",
143                                           err, *text, 0);
144                         }
145                         break;
146
147                 case LDAP_MOD_DELETE:
148                         if ( glue_attr_delete ) {
149                                 err = LDAP_SUCCESS;
150                                 break;
151                         }
152
153                         Debug(LDAP_DEBUG_ARGS,
154                                   "wt_modify_internal: delete %s\n",
155                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
156                         err = modify_delete_values( e, mod, get_permissiveModify(op),
157                                                                                 text, textbuf, textlen );
158                         if( err != LDAP_SUCCESS ) {
159                                 Debug(LDAP_DEBUG_ARGS,
160                                           "wt_modify_internal: %d %s\n", err, *text, 0);
161                         } else {
162                                 got_delete = 1;
163                         }
164                         break;
165
166                 case LDAP_MOD_REPLACE:
167                         Debug(LDAP_DEBUG_ARGS,
168                                   "wt_modify_internal: replace %s\n",
169                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
170                         err = modify_replace_values( e, mod, get_permissiveModify(op),
171                                                                                  text, textbuf, textlen );
172                         if( err != LDAP_SUCCESS ) {
173                                 Debug(LDAP_DEBUG_ARGS,
174                                           "wt_modify_internal: %d %s\n", err, *text, 0);
175                         } else {
176                                 got_delete = 1;
177                         }
178                         break;
179
180                 case LDAP_MOD_INCREMENT:
181                         Debug(LDAP_DEBUG_ARGS,
182                                   "wt_modify_internal: increment %s\n",
183                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
184                         err = modify_increment_values( e, mod, get_permissiveModify(op),
185                                                                                    text, textbuf, textlen );
186                         if( err != LDAP_SUCCESS ) {
187                                 Debug(LDAP_DEBUG_ARGS,
188                                           "wt_modify_internal: %d %s\n",
189                                           err, *text, 0);
190                         } else {
191                                 got_delete = 1;
192                         }
193                         break;
194
195                 case SLAP_MOD_SOFTADD:
196                         Debug(LDAP_DEBUG_ARGS,
197                                   "wt_modify_internal: softadd %s\n",
198                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
199                         /* Avoid problems in index_add_mods()
200                          * We need to add index if necessary.
201                          */
202                         mod->sm_op = LDAP_MOD_ADD;
203
204                         err = modify_add_values( e, mod, get_permissiveModify(op),
205                                 text, textbuf, textlen );
206
207                         mod->sm_op = SLAP_MOD_SOFTADD;
208
209                         if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
210                                 err = LDAP_SUCCESS;
211                         }
212
213                         if( err != LDAP_SUCCESS ) {
214                                 Debug(LDAP_DEBUG_ARGS, "wt_modify_internal: %d %s\n",
215                                         err, *text, 0);
216                         }
217                         break;
218
219                 case SLAP_MOD_SOFTDEL:
220                         Debug(LDAP_DEBUG_ARGS,
221                                   "wt_modify_internal: softdel %s\n",
222                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
223                         /* Avoid problems in index_delete_mods()
224                          * We need to add index if necessary.
225                          */
226                         mod->sm_op = LDAP_MOD_DELETE;
227
228                         err = modify_delete_values( e, mod, get_permissiveModify(op),
229                                                                                 text, textbuf, textlen );
230
231                         mod->sm_op = SLAP_MOD_SOFTDEL;
232
233                         if ( err == LDAP_SUCCESS ) {
234                                 got_delete = 1;
235                         } else if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
236                                 err = LDAP_SUCCESS;
237                         }
238
239                         if( err != LDAP_SUCCESS ) {
240                                 Debug(LDAP_DEBUG_ARGS, "wt_modify_internal: %d %s\n",
241                                           err, *text, 0);
242                         }
243                         break;
244
245                 case SLAP_MOD_ADD_IF_NOT_PRESENT:
246                         if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) {
247                                 /* skip */
248                                 err = LDAP_SUCCESS;
249                                 break;
250                         }
251
252                         Debug(LDAP_DEBUG_ARGS,
253                                   "wt_modify_internal: add_if_not_present %s\n",
254                                   mod->sm_desc->ad_cname.bv_val, 0, 0);
255                         /* Avoid problems in index_add_mods()
256                          * We need to add index if necessary.
257                          */
258                         mod->sm_op = LDAP_MOD_ADD;
259
260                         err = modify_add_values( e, mod, get_permissiveModify(op),
261                                                                          text, textbuf, textlen );
262
263                         mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
264
265                         if( err != LDAP_SUCCESS ) {
266                                 Debug(LDAP_DEBUG_ARGS, "wt_modify_internal: %d %s\n",
267                                           err, *text, 0);
268                         }
269                         break;
270
271                 default:
272                         Debug(LDAP_DEBUG_ANY, "wt_modify_internal: invalid op %d\n",
273                                   mod->sm_op, 0, 0);
274                         *text = "Invalid modify operation";
275                         err = LDAP_OTHER;
276                         Debug(LDAP_DEBUG_ARGS, "wt_modify_internal: %d %s\n",
277                                   err, *text, 0);
278                 }
279
280                 if ( err != LDAP_SUCCESS ) {
281                         attrs_free( e->e_attrs );
282                         e->e_attrs = save_attrs;
283                         /* unlock entry, delete from cache */
284                         return err;
285                 }
286
287                 /* If objectClass was modified, reset the flags */
288                 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
289                         e->e_ocflags = 0;
290                 }
291
292                 if ( glue_attr_delete ) e->e_ocflags = 0;
293
294
295                 /* check if modified attribute was indexed
296                  * but not in case of NOOP... */
297                 if ( !op->o_noop ) {
298                         wt_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs );
299                 }
300
301         }
302
303         /* check that the entry still obeys the schema */
304         ap = NULL;
305         rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap,
306                 text, textbuf, textlen );
307         if ( rc != LDAP_SUCCESS || op->o_noop ) {
308                 attrs_free( e->e_attrs );
309                 /* clear the indexing flags */
310                 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
311                         ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
312                 }
313                 e->e_attrs = save_attrs;
314
315                 if ( rc != LDAP_SUCCESS ) {
316                         Debug( LDAP_DEBUG_ANY,
317                                 "entry failed schema check: %s\n",
318                                 *text, 0, 0 );
319                 }
320
321                 /* if NOOP then silently revert to saved attrs */
322                 return rc;
323         }
324
325         /* structuralObjectClass modified! */
326         if ( ap ) {
327                 assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass );
328                 if ( !op->o_noop ) {
329                         wt_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass,
330                                                                 1, e->e_attrs, save_attrs );
331                 }
332         }
333
334         /* update the indices of the modified attributes */
335
336         /* start with deleting the old index entries */
337         for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
338                 if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
339                         struct berval *vals;
340                         Attribute *a2;
341                         ap->a_flags &= ~SLAP_ATTR_IXDEL;
342                         a2 = attr_find( e->e_attrs, ap->a_desc );
343                         if ( a2 ) {
344                                 /* need to detect which values were deleted */
345                                 int i, j;
346                                 /* let add know there were deletes */
347                                 if ( a2->a_flags & SLAP_ATTR_IXADD )
348                                         a2->a_flags |= SLAP_ATTR_IXDEL;
349                                 vals = op->o_tmpalloc( (ap->a_numvals + 1) *
350                                         sizeof(struct berval), op->o_tmpmemctx );
351                                 j = 0;
352                                 for ( i=0; i < ap->a_numvals; i++ ) {
353                                         rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
354                                                 &ap->a_nvals[i], NULL, op->o_tmpmemctx );
355                                         /* Save deleted values */
356                                         if ( rc == LDAP_NO_SUCH_ATTRIBUTE )
357                                                 vals[j++] = ap->a_nvals[i];
358                                 }
359                                 BER_BVZERO(vals+j);
360                         } else {
361                                 /* attribute was completely deleted */
362                                 vals = ap->a_nvals;
363                         }
364                         rc = 0;
365                         if ( !BER_BVISNULL( vals )) {
366                                 rc = wt_index_values( op, wc, ap->a_desc,
367                                                                           vals, e->e_id, SLAP_INDEX_DELETE_OP );
368                                 if ( rc != LDAP_SUCCESS ) {
369                                         Debug( LDAP_DEBUG_ANY,
370                                                    "%s: attribute \"%s\" index delete failure\n",
371                                                    op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
372                                         attrs_free( e->e_attrs );
373                                         e->e_attrs = save_attrs;
374                                 }
375                         }
376                         if ( vals != ap->a_nvals )
377                                 op->o_tmpfree( vals, op->o_tmpmemctx );
378                         if ( rc ) return rc;
379                 }
380         }
381
382         /* add the new index entries */
383         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
384                 if (ap->a_flags & SLAP_ATTR_IXADD) {
385                         ap->a_flags &= ~SLAP_ATTR_IXADD;
386                         if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
387                                 /* if any values were deleted, we must readd index
388                                  * for all remaining values.
389                                  */
390                                 ap->a_flags &= ~SLAP_ATTR_IXDEL;
391                                 rc = wt_index_values( op, wc, ap->a_desc, ap->a_nvals,
392                                                                           e->e_id, SLAP_INDEX_ADD_OP );
393                         } else {
394                                 int found = 0;
395                                 /* if this was only an add, we only need to index
396                                  * the added values.
397                                  */
398                                 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
399                                         struct berval *vals;
400                                         if ( ml->sml_desc != ap->a_desc || !ml->sml_numvals )
401                                                 continue;
402                                         found = 1;
403                                         switch( ml->sml_op ) {
404                                         case LDAP_MOD_ADD:
405                                         case LDAP_MOD_REPLACE:
406                                         case LDAP_MOD_INCREMENT:
407                                         case SLAP_MOD_SOFTADD:
408                                         case SLAP_MOD_ADD_IF_NOT_PRESENT:
409                                                 if ( ml->sml_op == LDAP_MOD_INCREMENT )
410                                                         vals = ap->a_nvals;
411                                                 else if ( ml->sml_nvalues )
412                                                         vals = ml->sml_nvalues;
413                                                 else
414                                                         vals = ml->sml_values;
415                                                 rc = wt_index_values( op, wc, ap->a_desc,
416                                                                                           vals, e->e_id, SLAP_INDEX_ADD_OP );
417                                                 break;
418                                         }
419                                         if ( rc )
420                                                 break;
421                                 }
422                                 /* This attr was affected by a modify of a subtype, so
423                                  * there was no direct match in the modlist. Just readd
424                                  * all of its values.
425                                  */
426                                 if ( !found ) {
427                                         rc = wt_index_values( op, wc, ap->a_desc, ap->a_nvals,
428                                                                                   e->e_id, SLAP_INDEX_ADD_OP );
429                                 }
430                         }
431                         if ( rc != LDAP_SUCCESS ) {
432                                 Debug( LDAP_DEBUG_ANY,
433                                        "%s: attribute \"%s\" index add failure\n",
434                                            op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 );
435                                 attrs_free( e->e_attrs );
436                                 e->e_attrs = save_attrs;
437                                 return rc;
438                         }
439                 }
440         }
441
442         return rc;
443 }
444
445 int
446 wt_modify( Operation *op, SlapReply *rs )
447 {
448         struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
449         wt_ctx *wc = NULL;
450         Entry           *e = NULL;
451         int             manageDSAit = get_manageDSAit( op );
452         char textbuf[SLAP_TEXT_BUFLEN];
453         size_t textlen = sizeof textbuf;
454         Entry           dummy = {0};
455
456         LDAPControl **preread_ctrl = NULL;
457         LDAPControl **postread_ctrl = NULL;
458         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
459         int num_ctrls = 0;
460
461         int rc;
462
463         Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(wt_modify) ": %s\n",
464                    op->o_req_dn.bv_val, 0, 0 );
465
466 #ifdef LDAP_X_TXN
467         if( op->o_txnSpec && txn_preop( op, rs ))
468                 return rs->sr_err;
469 #endif
470
471         ctrls[num_ctrls] = NULL;
472
473         wc = wt_ctx_get(op, wi);
474         if( !wc ){
475         Debug( LDAP_DEBUG_ANY,
476                            LDAP_XSTRING(wt_add)
477                            ": wt_ctx_get failed\n",
478                            0, 0, 0 );
479                 rs->sr_err = LDAP_OTHER;
480                 rs->sr_text = "internal error";
481         send_ldap_result( op, rs );
482         return rs->sr_err;
483         }
484
485         /* Don't touch the opattrs, if this is a contextCSN update
486          * initiated from updatedn */
487         if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next ||
488                  op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) {
489
490                 slap_mods_opattrs( op, &op->orm_modlist, 1 );
491         }
492
493         /* get entry */
494         rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
495         switch( rc ) {
496         case 0:
497                 break;
498         case WT_NOTFOUND:
499                 Debug( LDAP_DEBUG_ARGS,
500                            "<== " LDAP_XSTRING(wt_delete)
501                            ": no such object %s\n",
502                            op->o_req_dn.bv_val, 0, 0);
503                 /* TODO: lookup referrals */
504                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
505                 goto return_results;
506         default:
507                 Debug( LDAP_DEBUG_ANY,
508                            LDAP_XSTRING(wt_modify)
509                            ": wt_dn2entry failed (%d)\n",
510                            rc, 0, 0 );
511                 rs->sr_err = LDAP_OTHER;
512                 rs->sr_text = "internal error";
513                 goto return_results;
514         }
515
516         if ( !manageDSAit && is_entry_referral( e ) ) {
517                 /* entry is a referral, don't allow modify */
518                 rs->sr_ref = get_entry_referrals( op, e );
519
520                 Debug( LDAP_DEBUG_TRACE,
521                            LDAP_XSTRING(wt_modify) ": entry is referral\n",
522                            0, 0, 0 );
523
524                 rs->sr_err = LDAP_REFERRAL;
525                 rs->sr_matched = e->e_name.bv_val;
526                 rs->sr_flags = REP_REF_MUSTBEFREED;
527                 send_ldap_result( op, rs );
528                 rs->sr_matched = NULL;
529                 goto done;
530         }
531
532         if ( get_assert( op ) &&
533                  ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
534         {
535                 rs->sr_err = LDAP_ASSERTION_FAILED;
536                 goto return_results;
537         }
538
539         if( op->o_preread ) {
540                 if( preread_ctrl == NULL ) {
541                         preread_ctrl = &ctrls[num_ctrls++];
542                         ctrls[num_ctrls] = NULL;
543                 }
544                 if ( slap_read_controls( op, rs, e,
545                         &slap_pre_read_bv, preread_ctrl ) )
546                 {
547                         Debug( LDAP_DEBUG_TRACE,
548                                 "<=- " LDAP_XSTRING(wt_modify) ": pre-read "
549                                 "failed!\n", 0, 0, 0 );
550                         if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
551                                 /* FIXME: is it correct to abort
552                                  * operation if control fails? */
553                                 goto return_results;
554                         }
555                 }
556         }
557
558         /* begin transaction */
559         rc = wc->session->begin_transaction(wc->session, NULL);
560         if( rc ) {
561                 Debug( LDAP_DEBUG_TRACE,
562                            LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n",
563                            wiredtiger_strerror(rc), rc, 0 );
564                 rs->sr_err = LDAP_OTHER;
565                 rs->sr_text = "begin_transaction failed";
566                 goto return_results;
567         }
568         Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(wt_modify) ": session id: %p\n",
569                    wc->session, 0, 0 );
570
571         /* Modify the entry */
572         dummy = *e;
573         rs->sr_err = wt_modify_internal( op, wc, op->orm_modlist,
574                                                                          &dummy, &rs->sr_text, textbuf, textlen );
575         if( rs->sr_err != LDAP_SUCCESS ) {
576                 Debug( LDAP_DEBUG_TRACE,
577                            LDAP_XSTRING(wt_modify) ": modify failed (%d)\n",
578                            rs->sr_err, 0, 0 );
579                 /* Only free attrs if they were dup'd.  */
580                 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
581                 goto return_results;
582         }
583
584         /* change the entry itself */
585         rs->sr_err = wt_id2entry_update( op, wc->session, &dummy );
586         if ( rs->sr_err != 0 ) {
587                 Debug( LDAP_DEBUG_TRACE,
588                            LDAP_XSTRING(wt_modify) ": id2entry update failed " "(%d)\n",
589                            rs->sr_err, 0, 0 );
590                 if ( rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ) {
591                         rs->sr_text = "entry too big";
592                 } else {
593                         rs->sr_err = LDAP_OTHER;
594                         rs->sr_text = "entry update failed";
595                 }
596                 goto return_results;
597         }
598
599         if( op->o_noop ) {
600                 wc->session->rollback_transaction(wc->session, NULL);
601                 rs->sr_err = LDAP_X_NO_OPERATION;
602                 goto return_results;
603         }
604
605         /* Only free attrs if they were dup'd.  */
606         if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
607
608         rc = wc->session->commit_transaction(wc->session, NULL);
609         if( rc ) {
610                 Debug( LDAP_DEBUG_TRACE,
611                            "<== " LDAP_XSTRING(wt_modify)
612                            ": commit failed: %s (%d)\n",
613                            wiredtiger_strerror(rc), rc, 0 );
614                 rs->sr_err = LDAP_OTHER;
615                 rs->sr_text = "commit failed";
616                 goto return_results;
617         }
618
619         Debug( LDAP_DEBUG_TRACE,
620                    LDAP_XSTRING(wt_modify) ": updated%s id=%08lx dn=\"%s\"\n",
621                    op->o_noop ? " (no-op)" : "",
622                    dummy.e_id, op->o_req_dn.bv_val );
623
624         if( op->o_postread ) {
625                 if( postread_ctrl == NULL ) {
626                         postread_ctrl = &ctrls[num_ctrls++];
627                         ctrls[num_ctrls] = NULL;
628                 }
629                 if( slap_read_controls( op, rs, &dummy,
630                                                                 &slap_post_read_bv, postread_ctrl ) )
631                 {
632                         Debug( LDAP_DEBUG_TRACE,
633                                    "<=- " LDAP_XSTRING(wt_modify)
634                                    ": post-read failed!\n", 0, 0, 0 );
635                         if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
636                                 /* FIXME: is it correct to abort
637                                  * operation if control fails? */
638                                 goto return_results;
639                         }
640                 }
641         }
642         if( num_ctrls ) rs->sr_ctrls = ctrls;
643
644         rs->sr_err = LDAP_SUCCESS;
645         rs->sr_text = NULL;
646
647 return_results:
648         if( dummy.e_attrs ) {
649                 attrs_free( dummy.e_attrs );
650         }
651         send_ldap_result( op, rs );
652
653 done:
654         slap_graduate_commit_csn( op );
655
656         if( e != NULL ) {
657                 wt_entry_return( e );
658         }
659
660         if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
661                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
662                 slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
663         }
664         if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
665                 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
666                 slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
667         }
668
669         rs->sr_text = NULL;
670
671         return rs->sr_err;
672 }
673
674 /*
675  * Local variables:
676  * indent-tabs-mode: t
677  * tab-width: 4
678  * c-basic-offset: 4
679  * End:
680  */