]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/delete.c
Eliminate unnecessary Op copies
[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         backsql_tree_delete_t   btd = { 0 };
340
341         int                     rc;
342
343         /*
344          * - perform an internal subtree search as the rootdn
345          * - for each entry
346          *      - check access
347          *      - check objectClass and delete method(s)
348          * - for each entry
349          *      - delete
350          * - if successful, commit
351          */
352
353         op2.o_tag = LDAP_REQ_SEARCH;
354         op2.o_protocol = LDAP_VERSION3;
355
356         btd.btd_op = op;
357         sc.sc_private = &btd;
358         sc.sc_response = backsql_tree_delete_search_cb;
359         op2.o_callback = &sc;
360
361         op2.o_dn = op->o_bd->be_rootdn;
362         op2.o_ndn = op->o_bd->be_rootndn;
363
364         op2.o_managedsait = SLAP_CONTROL_CRITICAL;
365
366         op2.ors_scope = LDAP_SCOPE_SUBTREE;
367         op2.ors_deref = LDAP_DEREF_NEVER;
368         op2.ors_slimit = SLAP_NO_LIMIT;
369         op2.ors_tlimit = SLAP_NO_LIMIT;
370         op2.ors_filter = slap_filter_objectClass_pres;
371         op2.ors_filterstr = *slap_filterstr_objectClass_pres;
372         op2.ors_attrs = slap_anlist_all_attributes;
373         op2.ors_attrsonly = 0;
374
375         rc = op->o_bd->be_search( &op2, &rs2 );
376         if ( rc != LDAP_SUCCESS ) {
377                 rc = rs->sr_err = btd.btd_rc;
378                 rs->sr_text = "subtree delete not possible";
379                 send_ldap_result( op, rs );
380                 goto clean;
381         }
382
383         for ( ; btd.btd_eid != NULL;
384                 btd.btd_eid = backsql_free_entryID( btd.btd_eid,
385                         1, op->o_tmpmemctx ) )
386         {
387                 Entry   *e = (void *)0xbad;
388                 rc = backsql_delete_int( op, rs, dbh, sthp, btd.btd_eid, &e );
389                 if ( rc != LDAP_SUCCESS ) {
390                         break;
391                 }
392         }
393
394 clean:;
395         for ( ; btd.btd_eid != NULL;
396                 btd.btd_eid = backsql_free_entryID( btd.btd_eid,
397                         1, op->o_tmpmemctx ) )
398                 ;
399
400         return rc;
401 }
402
403 int
404 backsql_delete( Operation *op, SlapReply *rs )
405 {
406         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
407         SQLHDBC                 dbh = SQL_NULL_HDBC;
408         SQLHSTMT                sth = SQL_NULL_HSTMT;
409         backsql_oc_map_rec      *oc = NULL;
410         backsql_srch_info       bsi = { 0 };
411         backsql_entryID         e_id = { 0 };
412         Entry                   d = { 0 }, p = { 0 }, *e = NULL;
413         struct berval           pdn = BER_BVNULL;
414         int                     manageDSAit = get_manageDSAit( op );
415
416         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n",
417                         op->o_req_ndn.bv_val, 0, 0 );
418
419         rs->sr_err = backsql_get_db_conn( op, &dbh );
420         if ( rs->sr_err != LDAP_SUCCESS ) {
421                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
422                         "could not get connection handle - exiting\n", 
423                         0, 0, 0 );
424                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
425                         ? "SQL-backend error" : NULL;
426                 e = NULL;
427                 goto done;
428         }
429
430         /*
431          * Get the entry
432          */
433         bsi.bsi_e = &d;
434         rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
435                         LDAP_SCOPE_BASE, 
436                         (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
437                         ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) );
438         switch ( rs->sr_err ) {
439         case LDAP_SUCCESS:
440                 break;
441
442         case LDAP_REFERRAL:
443                 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
444                                 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
445                 {
446                         rs->sr_err = LDAP_SUCCESS;
447                         rs->sr_text = NULL;
448                         rs->sr_matched = NULL;
449                         if ( rs->sr_ref ) {
450                                 ber_bvarray_free( rs->sr_ref );
451                                 rs->sr_ref = NULL;
452                         }
453                         break;
454                 }
455                 e = &d;
456                 /* fallthru */
457
458         default:
459                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
460                         "could not retrieve deleteDN ID - no such entry\n", 
461                         0, 0, 0 );
462                 if ( !BER_BVISNULL( &d.e_nname ) ) {
463                         /* FIXME: should always be true! */
464                         e = &d;
465
466                 } else {
467                         e = NULL;
468                 }
469                 goto done;
470         }
471
472         if ( get_assert( op ) &&
473                         ( test_filter( op, &d, get_assertion( op ) )
474                           != LDAP_COMPARE_TRUE ) )
475         {
476                 rs->sr_err = LDAP_ASSERTION_FAILED;
477                 e = &d;
478                 goto done;
479         }
480
481         if ( !access_allowed( op, &d, slap_schema.si_ad_entry, 
482                         NULL, ACL_WDEL, NULL ) )
483         {
484                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
485                         "no write access to entry\n", 
486                         0, 0, 0 );
487                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
488                 e = &d;
489                 goto done;
490         }
491
492         rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn );
493         switch ( rs->sr_err ) {
494         case LDAP_COMPARE_FALSE:
495                 rs->sr_err = LDAP_SUCCESS;
496                 break;
497
498         case LDAP_COMPARE_TRUE:
499 #ifdef SLAP_CONTROL_X_TREE_DELETE
500                 if ( get_treeDelete( op ) ) {
501                         rs->sr_err = LDAP_SUCCESS;
502                         break;
503                 }
504 #endif /* SLAP_CONTROL_X_TREE_DELETE */
505
506                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
507                         "entry \"%s\" has children\n",
508                         op->o_req_dn.bv_val, 0, 0 );
509                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
510                 rs->sr_text = "subordinate objects must be deleted first";
511                 /* fallthru */
512
513         default:
514                 e = &d;
515                 goto done;
516         }
517
518         assert( bsi.bsi_base_id.eid_oc != NULL );
519         oc = bsi.bsi_base_id.eid_oc;
520         if ( oc->bom_delete_proc == NULL ) {
521                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
522                         "delete procedure is not defined "
523                         "for this objectclass - aborting\n", 0, 0, 0 );
524                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
525                 rs->sr_text = "operation not permitted within namingContext";
526                 e = NULL;
527                 goto done;
528         }
529
530         /*
531          * Get the parent
532          */
533         e_id = bsi.bsi_base_id;
534         memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) );
535         if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
536                 dnParent( &op->o_req_ndn, &pdn );
537                 bsi.bsi_e = &p;
538                 rs->sr_err = backsql_init_search( &bsi, &pdn,
539                                 LDAP_SCOPE_BASE, 
540                                 (time_t)(-1), NULL, dbh, op, rs,
541                                 slap_anlist_no_attrs,
542                                 BACKSQL_ISF_GET_ENTRY );
543                 if ( rs->sr_err != LDAP_SUCCESS ) {
544                         Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
545                                 "could not retrieve deleteDN ID "
546                                 "- no such entry\n", 
547                                 0, 0, 0 );
548                         e = &p;
549                         goto done;
550                 }
551
552                 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
553
554                 /* check parent for "children" acl */
555                 if ( !access_allowed( op, &p, slap_schema.si_ad_children, 
556                                 NULL, ACL_WDEL, NULL ) )
557                 {
558                         Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
559                                 "no write access to parent\n", 
560                                 0, 0, 0 );
561                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
562                         e = &p;
563                         goto done;
564
565                 }
566         }
567
568         e = &d;
569 #ifdef SLAP_CONTROL_X_TREE_DELETE
570         if ( get_treeDelete( op ) ) {
571                 backsql_tree_delete( op, rs, dbh, &sth );
572                 if ( rs->sr_err == LDAP_OTHER || rs->sr_err == LDAP_SUCCESS )
573                 {
574                         e = NULL;
575                 }
576
577         } else
578 #endif /* SLAP_CONTROL_X_TREE_DELETE */
579         {
580                 backsql_delete_int( op, rs, dbh, &sth, &e_id, &e );
581         }
582
583         /*
584          * Commit only if all operations succeed
585          */
586         if ( sth != SQL_NULL_HSTMT ) {
587                 SQLUSMALLINT    CompletionType = SQL_ROLLBACK;
588         
589                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
590                         assert( e == NULL );
591                         CompletionType = SQL_COMMIT;
592                 }
593
594                 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
595         }
596
597 done:;
598         if ( e != NULL ) {
599                 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
600                                         ACL_DISCLOSE, NULL ) )
601                 {
602                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
603                         rs->sr_text = NULL;
604                         rs->sr_matched = NULL;
605                         if ( rs->sr_ref ) {
606                                 ber_bvarray_free( rs->sr_ref );
607                                 rs->sr_ref = NULL;
608                         }
609                 }
610         }
611
612         if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
613                 rs->sr_err = LDAP_X_NO_OPERATION;
614         }
615
616         send_ldap_result( op, rs );
617
618         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
619
620         if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
621                 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx );
622         }
623
624         if ( !BER_BVISNULL( &d.e_nname ) ) {
625                 backsql_entry_clean( op, &d );
626         }
627
628         if ( !BER_BVISNULL( &p.e_nname ) ) {
629                 backsql_entry_clean( op, &p );
630         }
631
632         if ( rs->sr_ref ) {
633                 ber_bvarray_free( rs->sr_ref );
634                 rs->sr_ref = NULL;
635         }
636
637         return rs->sr_err;
638 }
639