]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/delete.c
Fix ITS#3424
[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-2004 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
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 initially developed by Dmitry Kovalev for inclusion
18  * by OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include "ac/string.h"
26
27 #include "slap.h"
28 #include "proto-sql.h"
29
30 typedef struct backsql_delete_attr_t {
31         Operation               *op;
32         SlapReply               *rs;
33         SQLHDBC                 dbh; 
34         backsql_entryID         *e_id;
35 } backsql_delete_attr_t;
36
37 static int
38 backsql_delete_attr_f( void *v_at, void *v_bda )
39 {
40         backsql_at_map_rec      *at = (backsql_at_map_rec *)v_at;
41         backsql_delete_attr_t   *bda = (backsql_delete_attr_t *)v_bda;
42         int                     rc;
43
44         rc = backsql_modify_delete_all_values( bda->op,
45                         bda->rs, bda->dbh, bda->e_id, at );
46
47         if ( rc != LDAP_SUCCESS ) {
48                 return BACKSQL_AVL_STOP;
49         }
50
51         return BACKSQL_AVL_CONTINUE;
52 }
53
54 static int
55 backsql_delete_all_attrs(
56         Operation               *op,
57         SlapReply               *rs,
58         SQLHDBC                 dbh, 
59         backsql_entryID         *e_id,
60         backsql_oc_map_rec      *oc )
61 {
62         backsql_delete_attr_t   bda;
63         int                     rc;
64
65         bda.op = op;
66         bda.rs = rs;
67         bda.dbh = dbh;
68         bda.e_id = e_id;
69         
70         rc = avl_apply( oc->bom_attrs, backsql_delete_attr_f, &bda,
71                         BACKSQL_AVL_STOP, AVL_INORDER );
72         if ( rc == BACKSQL_AVL_STOP ) {
73                 return rs->sr_err;
74         }
75
76         return LDAP_SUCCESS;
77 }
78
79 int
80 backsql_delete( Operation *op, SlapReply *rs )
81 {
82         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
83         SQLHDBC                 dbh;
84         SQLHSTMT                sth;
85         RETCODE                 rc;
86         int                     retval;
87         backsql_oc_map_rec      *oc = NULL;
88         backsql_entryID         e_id = BACKSQL_ENTRYID_INIT;
89         Entry                   e;
90         /* first parameter no */
91         SQLUSMALLINT            pno;
92
93         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n",
94                         op->o_req_ndn.bv_val, 0, 0 );
95
96         dnParent( &op->o_req_dn, &e.e_name );
97         dnParent( &op->o_req_ndn, &e.e_nname );
98         e.e_attrs = NULL;
99
100         /* check parent for "children" acl */
101         if ( !access_allowed( op, &e, slap_schema.si_ad_children, 
102                         NULL, ACL_WRITE, NULL ) ) {
103                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
104                         "no write access to parent\n", 
105                         0, 0, 0 );
106                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
107                 goto done;
108
109         }
110         
111         rs->sr_err = backsql_get_db_conn( op, &dbh );
112         if ( rs->sr_err != LDAP_SUCCESS ) {
113                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
114                         "could not get connection handle - exiting\n", 
115                         0, 0, 0 );
116                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
117                         ? "SQL-backend error" : NULL;
118                 goto done;
119         }
120         
121         rs->sr_err = backsql_dn2id( op, rs, &e_id, dbh, &op->o_req_ndn, 1 );
122         if ( rs->sr_err != LDAP_SUCCESS ) {
123                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
124                         "could not lookup entry id\n", 0, 0, 0 );
125                 goto done;
126         }
127
128         rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn );
129         switch ( rs->sr_err ) {
130         case LDAP_COMPARE_TRUE:
131                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
132                         "entry \"%s\" has children\n",
133                         op->o_req_dn.bv_val, 0, 0 );
134                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
135                 rs->sr_text = "subtree delete not supported";
136                 goto done;
137
138         case LDAP_COMPARE_FALSE:
139                 break;
140
141         default:
142                 goto done;
143         }
144
145         oc = backsql_id2oc( bi, e_id.eid_oc_id );
146         if ( oc == NULL ) {
147                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
148                         "cannot determine objectclass of entry -- aborting\n",
149                         0, 0, 0 );
150                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
151                 rs->sr_text = "operation not permitted within namingContext";
152                 goto done;
153         }
154
155         if ( oc->bom_delete_proc == NULL ) {
156                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
157                         "delete procedure is not defined "
158                         "for this objectclass - aborting\n", 0, 0, 0 );
159                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
160                 rs->sr_text = "operation not permitted within namingContext";
161                 goto done;
162         }
163
164         /* avl_apply ... */
165         rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, &e_id, oc );
166         if ( rs->sr_err != LDAP_SUCCESS ) {
167                 goto done;
168         }
169
170         rc = backsql_Prepare( dbh, &sth, oc->bom_delete_proc, 0 );
171         if ( rc != SQL_SUCCESS ) {
172                 Debug( LDAP_DEBUG_TRACE,
173                         "   backsql_delete(): "
174                         "error preparing delete query\n", 
175                         0, 0, 0 );
176                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
177
178                 rs->sr_err = LDAP_OTHER;
179                 rs->sr_text = "SQL-backend error";
180                 goto done;
181         }
182
183         if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) {
184                 pno = 1;
185                 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &retval );
186                 if ( rc != SQL_SUCCESS ) {
187                         Debug( LDAP_DEBUG_TRACE,
188                                 "   backsql_delete(): "
189                                 "error binding output parameter for objectClass %s\n",
190                                 oc->bom_oc->soc_cname.bv_val, 0, 0 );
191                         backsql_PrintErrors( bi->sql_db_env, dbh, 
192                                 sth, rc );
193                         SQLFreeStmt( sth, SQL_DROP );
194
195                         rs->sr_text = "SQL-backend error";
196                         rs->sr_err = LDAP_OTHER;
197                         goto done;
198                 }
199
200         } else {
201                 pno = 0;
202         }
203
204         rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &e_id.eid_keyval );
205         if ( rc != SQL_SUCCESS ) {
206                 Debug( LDAP_DEBUG_TRACE,
207                         "   backsql_delete(): "
208                         "error binding keyval parameter for objectClass %s\n",
209                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
210                 backsql_PrintErrors( bi->sql_db_env, dbh, 
211                         sth, rc );
212                 SQLFreeStmt( sth, SQL_DROP );
213
214                 rs->sr_text = "SQL-backend error";
215                 rs->sr_err = LDAP_OTHER;
216                 goto done;
217         }
218
219         rc = SQLExecute( sth );
220         if ( rc != SQL_SUCCESS ) {
221                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
222                         "delete_proc execution failed\n", 0, 0, 0 );
223                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
224                 SQLFreeStmt( sth, SQL_DROP );
225                 rs->sr_err = LDAP_OTHER;
226                 rs->sr_text = "SQL-backend error";
227                 goto done;
228         }
229         SQLFreeStmt( sth, SQL_DROP );
230
231         /* delete "auxiliary" objectClasses, if any... */
232         rc = backsql_Prepare( dbh, &sth, bi->sql_delobjclasses_query, 0 );
233         if ( rc != SQL_SUCCESS ) {
234                 Debug( LDAP_DEBUG_TRACE,
235                         "   backsql_delete(): "
236                         "error preparing ldap_entry_objclasses 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                 goto done;
243         }
244
245         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
246         if ( rc != SQL_SUCCESS ) {
247                 Debug( LDAP_DEBUG_TRACE,
248                         "   backsql_delete(): "
249                         "error binding auxiliary objectClasses "
250                         "entry ID parameter for objectClass %s\n",
251                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
252                 backsql_PrintErrors( bi->sql_db_env, dbh, 
253                         sth, rc );
254                 SQLFreeStmt( sth, SQL_DROP );
255
256                 rs->sr_text = "SQL-backend error";
257                 rs->sr_err = LDAP_OTHER;
258                 goto done;
259         }
260
261         rc = SQLExecute( sth );
262         switch ( rc ) {
263         case SQL_NO_DATA:
264                 /* apparently there were no "auxiliary" objectClasses
265                  * for this entry... */
266         case SQL_SUCCESS:
267                 break;
268
269         default:
270                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
271                         "failed to delete record from ldap_entry_objclasses\n", 
272                         0, 0, 0 );
273                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
274                 SQLFreeStmt( sth, SQL_DROP );
275                 rs->sr_err = LDAP_OTHER;
276                 rs->sr_text = "SQL-backend error";
277                 goto done;
278         }
279         SQLFreeStmt( sth, SQL_DROP );
280
281         /* delete referrals, if any... */
282         rc = backsql_Prepare( dbh, &sth, bi->sql_delreferrals_query, 0 );
283         if ( rc != SQL_SUCCESS ) {
284                 Debug( LDAP_DEBUG_TRACE,
285                         "   backsql_delete(): "
286                         "error preparing ldap_referrals delete query\n", 
287                         0, 0, 0 );
288                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
289
290                 rs->sr_err = LDAP_OTHER;
291                 rs->sr_text = "SQL-backend error";
292                 goto done;
293         }
294
295         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
296         if ( rc != SQL_SUCCESS ) {
297                 Debug( LDAP_DEBUG_TRACE,
298                         "   backsql_delete(): "
299                         "error binding referrals entry ID parameter "
300                         "for objectClass %s\n",
301                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
302                 backsql_PrintErrors( bi->sql_db_env, dbh, 
303                         sth, rc );
304                 SQLFreeStmt( sth, SQL_DROP );
305
306                 rs->sr_text = "SQL-backend error";
307                 rs->sr_err = LDAP_OTHER;
308                 goto done;
309         }
310
311         rc = SQLExecute( sth );
312         switch ( rc ) {
313         case SQL_NO_DATA:
314                 /* apparently there were no referrals
315                  * for this entry... */
316         case SQL_SUCCESS:
317                 break;
318
319         default:
320                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
321                         "failed to delete record from ldap_referrals\n", 
322                         0, 0, 0 );
323                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
324                 SQLFreeStmt( sth, SQL_DROP );
325                 rs->sr_err = LDAP_OTHER;
326                 rs->sr_text = "SQL-backend error";
327                 goto done;
328         }
329         SQLFreeStmt( sth, SQL_DROP );
330
331         /* delete entry... */
332         rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_query, 0 );
333         if ( rc != SQL_SUCCESS ) {
334                 Debug( LDAP_DEBUG_TRACE,
335                         "   backsql_delete(): "
336                         "error preparing ldap_entries delete query\n", 
337                         0, 0, 0 );
338                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
339
340                 rs->sr_err = LDAP_OTHER;
341                 rs->sr_text = "SQL-backend error";
342                 goto done;
343         }
344
345         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
346         if ( rc != SQL_SUCCESS ) {
347                 Debug( LDAP_DEBUG_TRACE,
348                         "   backsql_delete(): "
349                         "error binding entry ID parameter "
350                         "for objectClass %s\n",
351                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
352                 backsql_PrintErrors( bi->sql_db_env, dbh, 
353                         sth, rc );
354                 SQLFreeStmt( sth, SQL_DROP );
355
356                 rs->sr_text = "SQL-backend error";
357                 rs->sr_err = LDAP_OTHER;
358                 goto done;
359         }
360
361         rc = SQLExecute( sth );
362         if ( rc != SQL_SUCCESS ) {
363                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
364                         "failed to delete record from ldap_entries\n", 
365                         0, 0, 0 );
366                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
367                 SQLFreeStmt( sth, SQL_DROP );
368                 rs->sr_err = LDAP_OTHER;
369                 rs->sr_text = "SQL-backend error";
370                 goto done;
371         }
372         SQLFreeStmt( sth, SQL_DROP );
373
374         /*
375          * Commit only if all operations succeed
376          *
377          * FIXME: backsql_add() does not fail if add operations 
378          * are not available for some attributes, or if
379          * a multiple value add actually results in a replace, 
380          * or if a single operation on an attribute fails 
381          * for any reason
382          */
383         SQLTransact( SQL_NULL_HENV, dbh, 
384                         op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
385
386         rs->sr_err = LDAP_SUCCESS;
387
388 done:;
389         send_ldap_result( op, rs );
390
391         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
392
393         return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
394 }
395