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