]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/delete.c
Hide log schema
[openldap] / servers / slapd / back-sql / delete.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2007 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Dmitry Kovalev for inclusion
19  * by OpenLDAP Software.  Additional significant contributors include
20  * Pierangelo Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "proto-sql.h"
31
32 typedef struct backsql_delete_attr_t {
33         Operation               *op;
34         SlapReply               *rs;
35         SQLHDBC                 dbh; 
36         backsql_entryID         *e_id;
37 } backsql_delete_attr_t;
38
39 static int
40 backsql_delete_attr_f( void *v_at, void *v_bda )
41 {
42         backsql_at_map_rec      *at = (backsql_at_map_rec *)v_at;
43         backsql_delete_attr_t   *bda = (backsql_delete_attr_t *)v_bda;
44         int                     rc;
45
46         rc = backsql_modify_delete_all_values( bda->op,
47                         bda->rs, bda->dbh, bda->e_id, at );
48
49         if ( rc != LDAP_SUCCESS ) {
50                 return BACKSQL_AVL_STOP;
51         }
52
53         return BACKSQL_AVL_CONTINUE;
54 }
55
56 static int
57 backsql_delete_all_attrs(
58         Operation               *op,
59         SlapReply               *rs,
60         SQLHDBC                 dbh, 
61         backsql_entryID         *eid )
62 {
63         backsql_delete_attr_t   bda;
64         int                     rc;
65
66         bda.op = op;
67         bda.rs = rs;
68         bda.dbh = dbh;
69         bda.e_id = eid;
70         
71         rc = avl_apply( eid->eid_oc->bom_attrs, backsql_delete_attr_f, &bda,
72                         BACKSQL_AVL_STOP, AVL_INORDER );
73         if ( rc == BACKSQL_AVL_STOP ) {
74                 return rs->sr_err;
75         }
76
77         return LDAP_SUCCESS;
78 }
79
80 static int
81 backsql_delete_int(
82         Operation       *op,
83         SlapReply       *rs,
84         SQLHDBC         dbh,
85         SQLHSTMT        *sthp,
86         backsql_entryID *eid,
87         Entry           **ep )
88 {
89         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
90         SQLHSTMT                sth = SQL_NULL_HSTMT;
91         RETCODE                 rc;
92         int                     prc = LDAP_SUCCESS;
93         /* first parameter no */
94         SQLUSMALLINT            pno = 0;
95
96         sth = *sthp;
97
98         /* avl_apply ... */
99         rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, eid );
100         if ( rs->sr_err != LDAP_SUCCESS ) {
101                 goto done;
102         }
103
104         rc = backsql_Prepare( dbh, &sth, eid->eid_oc->bom_delete_proc, 0 );
105         if ( rc != SQL_SUCCESS ) {
106                 Debug( LDAP_DEBUG_TRACE,
107                         "   backsql_delete(): "
108                         "error preparing delete query\n", 
109                         0, 0, 0 );
110                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
111
112                 rs->sr_err = LDAP_OTHER;
113                 rs->sr_text = "SQL-backend error";
114                 *ep = NULL;
115                 goto done;
116         }
117
118         if ( BACKSQL_IS_DEL( eid->eid_oc->bom_expect_return ) ) {
119                 pno = 1;
120                 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
121                 if ( rc != SQL_SUCCESS ) {
122                         Debug( LDAP_DEBUG_TRACE,
123                                 "   backsql_delete(): "
124                                 "error binding output parameter for objectClass %s\n",
125                                 eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 );
126                         backsql_PrintErrors( bi->sql_db_env, dbh, 
127                                 sth, rc );
128                         SQLFreeStmt( sth, SQL_DROP );
129
130                         rs->sr_text = "SQL-backend error";
131                         rs->sr_err = LDAP_OTHER;
132                         *ep = NULL;
133                         goto done;
134                 }
135         }
136
137         rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &eid->eid_keyval );
138         if ( rc != SQL_SUCCESS ) {
139                 Debug( LDAP_DEBUG_TRACE,
140                         "   backsql_delete(): "
141                         "error binding keyval parameter for objectClass %s\n",
142                         eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 );
143                 backsql_PrintErrors( bi->sql_db_env, dbh, 
144                         sth, rc );
145                 SQLFreeStmt( sth, SQL_DROP );
146
147                 rs->sr_text = "SQL-backend error";
148                 rs->sr_err = LDAP_OTHER;
149                 *ep = NULL;
150                 goto done;
151         }
152
153         rc = SQLExecute( sth );
154         if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
155                 rs->sr_err = LDAP_SUCCESS;
156
157         } else {
158                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
159                         "delete_proc execution failed (rc=%d, prc=%d)\n",
160                         rc, prc, 0 );
161
162
163                 if ( prc != LDAP_SUCCESS ) {
164                         /* SQL procedure executed fine 
165                          * but returned an error */
166                         rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
167
168                 } else {
169                         backsql_PrintErrors( bi->sql_db_env, dbh,
170                                         sth, rc );
171                         rs->sr_err = LDAP_OTHER;
172                 }
173                 SQLFreeStmt( sth, SQL_DROP );
174                 goto done;
175         }
176         SQLFreeStmt( sth, SQL_DROP );
177
178         /* delete "auxiliary" objectClasses, if any... */
179         rc = backsql_Prepare( dbh, &sth, bi->sql_delobjclasses_stmt, 0 );
180         if ( rc != SQL_SUCCESS ) {
181                 Debug( LDAP_DEBUG_TRACE,
182                         "   backsql_delete(): "
183                         "error preparing ldap_entry_objclasses delete query\n", 
184                         0, 0, 0 );
185                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
186
187                 rs->sr_err = LDAP_OTHER;
188                 rs->sr_text = "SQL-backend error";
189                 *ep = NULL;
190                 goto done;
191         }
192
193         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id );
194         if ( rc != SQL_SUCCESS ) {
195                 Debug( LDAP_DEBUG_TRACE,
196                         "   backsql_delete(): "
197                         "error binding auxiliary objectClasses "
198                         "entry ID parameter for objectClass %s\n",
199                         eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 );
200                 backsql_PrintErrors( bi->sql_db_env, dbh, 
201                         sth, rc );
202                 SQLFreeStmt( sth, SQL_DROP );
203
204                 rs->sr_text = "SQL-backend error";
205                 rs->sr_err = LDAP_OTHER;
206                 *ep = NULL;
207                 goto done;
208         }
209
210         rc = SQLExecute( sth );
211         switch ( rc ) {
212         case SQL_NO_DATA:
213                 /* apparently there were no "auxiliary" objectClasses
214                  * for this entry... */
215         case SQL_SUCCESS:
216                 break;
217
218         default:
219                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
220                         "failed to delete record from ldap_entry_objclasses\n", 
221                         0, 0, 0 );
222                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
223                 SQLFreeStmt( sth, SQL_DROP );
224                 rs->sr_err = LDAP_OTHER;
225                 rs->sr_text = "SQL-backend error";
226                 *ep = NULL;
227                 goto done;
228         }
229         SQLFreeStmt( sth, SQL_DROP );
230
231         /* delete entry... */
232         rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_stmt, 0 );
233         if ( rc != SQL_SUCCESS ) {
234                 Debug( LDAP_DEBUG_TRACE,
235                         "   backsql_delete(): "
236                         "error preparing ldap_entries delete query\n", 
237                         0, 0, 0 );
238                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
239
240                 rs->sr_err = LDAP_OTHER;
241                 rs->sr_text = "SQL-backend error";
242                 *ep = NULL;
243                 goto done;
244         }
245
246         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id );
247         if ( rc != SQL_SUCCESS ) {
248                 Debug( LDAP_DEBUG_TRACE,
249                         "   backsql_delete(): "
250                         "error binding entry ID parameter "
251                         "for objectClass %s\n",
252                         eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 );
253                 backsql_PrintErrors( bi->sql_db_env, dbh, 
254                         sth, rc );
255                 SQLFreeStmt( sth, SQL_DROP );
256
257                 rs->sr_text = "SQL-backend error";
258                 rs->sr_err = LDAP_OTHER;
259                 *ep = NULL;
260                 goto done;
261         }
262
263         rc = SQLExecute( sth );
264         if ( rc != SQL_SUCCESS ) {
265                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
266                         "failed to delete record from ldap_entries\n", 
267                         0, 0, 0 );
268                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
269                 SQLFreeStmt( sth, SQL_DROP );
270                 rs->sr_err = LDAP_OTHER;
271                 rs->sr_text = "SQL-backend error";
272                 *ep = NULL;
273                 goto done;
274         }
275         SQLFreeStmt( sth, SQL_DROP );
276
277         rs->sr_err = LDAP_SUCCESS;
278         *ep = NULL;
279
280 done:;
281         *sthp = sth;
282
283         return rs->sr_err;
284 }
285
286 typedef struct backsql_tree_delete_t {
287         Operation       *btd_op;
288         int             btd_rc;
289         backsql_entryID *btd_eid;
290 } backsql_tree_delete_t;
291
292 static int
293 backsql_tree_delete_search_cb( Operation *op, SlapReply *rs )
294 {
295         if ( rs->sr_type == REP_SEARCH ) {
296                 backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
297                 backsql_tree_delete_t   *btd;
298                 backsql_entryID         *eid;
299
300                 btd = (backsql_tree_delete_t *)op->o_callback->sc_private;
301
302                 if ( !access_allowed( btd->btd_op, rs->sr_entry,
303                         slap_schema.si_ad_entry, NULL, ACL_WDEL, NULL )
304                         || !access_allowed( btd->btd_op, rs->sr_entry,
305                         slap_schema.si_ad_children, NULL, ACL_WDEL, NULL ) )
306                 {
307                         btd->btd_rc = LDAP_INSUFFICIENT_ACCESS;
308                         return rs->sr_err = LDAP_UNAVAILABLE;
309                 }
310
311                 assert( rs->sr_entry != NULL );
312                 assert( rs->sr_entry->e_private != NULL );
313
314                 eid = (backsql_entryID *)rs->sr_entry->e_private;
315                 assert( eid->eid_oc != NULL );
316                 if ( eid->eid_oc == NULL || eid->eid_oc->bom_delete_proc == NULL ) {
317                         btd->btd_rc = LDAP_UNWILLING_TO_PERFORM;
318                         return rs->sr_err = LDAP_UNAVAILABLE;
319                 }
320
321                 eid = backsql_entryID_dup( eid, op->o_tmpmemctx );
322                 eid->eid_next = btd->btd_eid;
323                 btd->btd_eid = eid;
324         }
325
326         return 0;
327 }
328
329 static int
330 backsql_tree_delete(
331         Operation       *op,
332         SlapReply       *rs,
333         SQLHDBC         dbh,
334         SQLHSTMT        *sthp )
335 {
336         Operation               op2 = *op;
337         slap_callback           sc = { 0 };
338         SlapReply               rs2 = { 0 };
339         Filter                  f = { 0 };
340         backsql_tree_delete_t   btd = { 0 };
341
342         int                     rc;
343
344         /*
345          * - perform an internal subtree search as the rootdn
346          * - for each entry
347          *      - check access
348          *      - check objectClass and delete method(s)
349          * - for each entry
350          *      - delete
351          * - if successful, commit
352          */
353
354         op2.o_tag = LDAP_REQ_SEARCH;
355         op2.o_protocol = LDAP_VERSION3;
356
357         btd.btd_op = op;
358         sc.sc_private = &btd;
359         sc.sc_response = backsql_tree_delete_search_cb;
360         op2.o_callback = &sc;
361
362         op2.o_dn = op->o_bd->be_rootdn;
363         op2.o_ndn = op->o_bd->be_rootndn;
364
365         op2.o_managedsait = SLAP_CONTROL_CRITICAL;
366
367         op2.ors_scope = LDAP_SCOPE_SUBTREE;
368         op2.ors_deref = LDAP_DEREF_NEVER;
369         op2.ors_slimit = SLAP_NO_LIMIT;
370         op2.ors_tlimit = SLAP_NO_LIMIT;
371         op2.ors_filter = &f;
372         f.f_choice = LDAP_FILTER_PRESENT;
373         f.f_desc = slap_schema.si_ad_objectClass;
374         BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" );
375         op2.ors_attrs = slap_anlist_all_attributes;
376         op2.ors_attrsonly = 0;
377
378         rc = op->o_bd->be_search( &op2, &rs2 );
379         if ( rc != LDAP_SUCCESS ) {
380                 rc = rs->sr_err = btd.btd_rc;
381                 rs->sr_text = "subtree delete not possible";
382                 send_ldap_result( op, rs );
383                 goto clean;
384         }
385
386         for ( ; btd.btd_eid != NULL;
387                 btd.btd_eid = backsql_free_entryID( btd.btd_eid,
388                         1, op->o_tmpmemctx ) )
389         {
390                 Entry   *e = (void *)0xbad;
391                 rc = backsql_delete_int( op, rs, dbh, sthp, btd.btd_eid, &e );
392                 if ( rc != LDAP_SUCCESS ) {
393                         break;
394                 }
395         }
396
397 clean:;
398         for ( ; btd.btd_eid != NULL;
399                 btd.btd_eid = backsql_free_entryID( btd.btd_eid,
400                         1, op->o_tmpmemctx ) )
401                 ;
402
403         return rc;
404 }
405
406 int
407 backsql_delete( Operation *op, SlapReply *rs )
408 {
409         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
410         SQLHDBC                 dbh = SQL_NULL_HDBC;
411         SQLHSTMT                sth = SQL_NULL_HSTMT;
412         backsql_oc_map_rec      *oc = NULL;
413         backsql_srch_info       bsi = { 0 };
414         backsql_entryID         e_id = { 0 };
415         Entry                   d = { 0 }, p = { 0 }, *e = NULL;
416         struct berval           pdn = BER_BVNULL;
417         int                     manageDSAit = get_manageDSAit( op );
418
419         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n",
420                         op->o_req_ndn.bv_val, 0, 0 );
421
422         rs->sr_err = backsql_get_db_conn( op, &dbh );
423         if ( rs->sr_err != LDAP_SUCCESS ) {
424                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
425                         "could not get connection handle - exiting\n", 
426                         0, 0, 0 );
427                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
428                         ? "SQL-backend error" : NULL;
429                 e = NULL;
430                 goto done;
431         }
432
433         /*
434          * Get the entry
435          */
436         bsi.bsi_e = &d;
437         rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
438                         LDAP_SCOPE_BASE, 
439                         (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
440                         ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) );
441         switch ( rs->sr_err ) {
442         case LDAP_SUCCESS:
443                 break;
444
445         case LDAP_REFERRAL:
446                 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
447                                 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
448                 {
449                         rs->sr_err = LDAP_SUCCESS;
450                         rs->sr_text = NULL;
451                         rs->sr_matched = NULL;
452                         if ( rs->sr_ref ) {
453                                 ber_bvarray_free( rs->sr_ref );
454                                 rs->sr_ref = NULL;
455                         }
456                         break;
457                 }
458                 e = &d;
459                 /* fallthru */
460
461         default:
462                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
463                         "could not retrieve deleteDN ID - no such entry\n", 
464                         0, 0, 0 );
465                 if ( !BER_BVISNULL( &d.e_nname ) ) {
466                         /* FIXME: should always be true! */
467                         e = &d;
468
469                 } else {
470                         e = NULL;
471                 }
472                 goto done;
473         }
474
475         if ( get_assert( op ) &&
476                         ( test_filter( op, &d, get_assertion( op ) )
477                           != LDAP_COMPARE_TRUE ) )
478         {
479                 rs->sr_err = LDAP_ASSERTION_FAILED;
480                 e = &d;
481                 goto done;
482         }
483
484         if ( !access_allowed( op, &d, slap_schema.si_ad_entry, 
485                         NULL, ACL_WDEL, NULL ) )
486         {
487                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
488                         "no write access to entry\n", 
489                         0, 0, 0 );
490                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
491                 e = &d;
492                 goto done;
493         }
494
495         rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn );
496         switch ( rs->sr_err ) {
497         case LDAP_COMPARE_FALSE:
498                 rs->sr_err = LDAP_SUCCESS;
499                 break;
500
501         case LDAP_COMPARE_TRUE:
502 #ifdef SLAP_CONTROL_X_TREE_DELETE
503                 if ( get_treeDelete( op ) ) {
504                         rs->sr_err = LDAP_SUCCESS;
505                         break;
506                 }
507 #endif /* SLAP_CONTROL_X_TREE_DELETE */
508
509                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
510                         "entry \"%s\" has children\n",
511                         op->o_req_dn.bv_val, 0, 0 );
512                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
513                 rs->sr_text = "subordinate objects must be deleted first";
514                 /* fallthru */
515
516         default:
517                 e = &d;
518                 goto done;
519         }
520
521         assert( bsi.bsi_base_id.eid_oc != NULL );
522         oc = bsi.bsi_base_id.eid_oc;
523         if ( oc->bom_delete_proc == NULL ) {
524                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
525                         "delete procedure is not defined "
526                         "for this objectclass - aborting\n", 0, 0, 0 );
527                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
528                 rs->sr_text = "operation not permitted within namingContext";
529                 e = NULL;
530                 goto done;
531         }
532
533         /*
534          * Get the parent
535          */
536         e_id = bsi.bsi_base_id;
537         memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) );
538         if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
539                 dnParent( &op->o_req_ndn, &pdn );
540                 bsi.bsi_e = &p;
541                 rs->sr_err = backsql_init_search( &bsi, &pdn,
542                                 LDAP_SCOPE_BASE, 
543                                 (time_t)(-1), NULL, dbh, op, rs,
544                                 slap_anlist_no_attrs,
545                                 BACKSQL_ISF_GET_ENTRY );
546                 if ( rs->sr_err != LDAP_SUCCESS ) {
547                         Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
548                                 "could not retrieve deleteDN ID "
549                                 "- no such entry\n", 
550                                 0, 0, 0 );
551                         e = &p;
552                         goto done;
553                 }
554
555                 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
556
557                 /* check parent for "children" acl */
558                 if ( !access_allowed( op, &p, slap_schema.si_ad_children, 
559                                 NULL, ACL_WDEL, NULL ) )
560                 {
561                         Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
562                                 "no write access to parent\n", 
563                                 0, 0, 0 );
564                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
565                         e = &p;
566                         goto done;
567
568                 }
569         }
570
571         e = &d;
572 #ifdef SLAP_CONTROL_X_TREE_DELETE
573         if ( get_treeDelete( op ) ) {
574                 backsql_tree_delete( op, rs, dbh, &sth );
575                 if ( rs->sr_err == LDAP_OTHER || rs->sr_err == LDAP_SUCCESS )
576                 {
577                         e = NULL;
578                 }
579
580         } else
581 #endif /* SLAP_CONTROL_X_TREE_DELETE */
582         {
583                 backsql_delete_int( op, rs, dbh, &sth, &e_id, &e );
584         }
585
586         /*
587          * Commit only if all operations succeed
588          */
589         if ( sth != SQL_NULL_HSTMT ) {
590                 SQLUSMALLINT    CompletionType = SQL_ROLLBACK;
591         
592                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
593                         assert( e == NULL );
594                         CompletionType = SQL_COMMIT;
595                 }
596
597                 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
598         }
599
600 done:;
601         if ( e != NULL ) {
602                 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
603                                         ACL_DISCLOSE, NULL ) )
604                 {
605                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
606                         rs->sr_text = NULL;
607                         rs->sr_matched = NULL;
608                         if ( rs->sr_ref ) {
609                                 ber_bvarray_free( rs->sr_ref );
610                                 rs->sr_ref = NULL;
611                         }
612                 }
613         }
614
615         if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
616                 rs->sr_err = LDAP_X_NO_OPERATION;
617         }
618
619         send_ldap_result( op, rs );
620
621         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
622
623         if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
624                 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx );
625         }
626
627         if ( !BER_BVISNULL( &d.e_nname ) ) {
628                 backsql_entry_clean( op, &d );
629         }
630
631         if ( !BER_BVISNULL( &p.e_nname ) ) {
632                 backsql_entry_clean( op, &p );
633         }
634
635         if ( rs->sr_ref ) {
636                 ber_bvarray_free( rs->sr_ref );
637                 rs->sr_ref = NULL;
638         }
639
640         return rs->sr_err;
641 }
642