X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=servers%2Fslapd%2Fback-sql%2Fdelete.c;h=a95188642230d72c945faeb05eed2de2a801fc6a;hb=ea026cb2cf048c3700042e9776b183ddda1120a4;hp=5cf9b6456eeec29784f9d631c6076536d817b465;hpb=fa8ee16d38e885d83118f70577d8362ed6c582ae;p=openldap diff --git a/servers/slapd/back-sql/delete.c b/servers/slapd/back-sql/delete.c index 5cf9b6456e..a951886422 100644 --- a/servers/slapd/back-sql/delete.c +++ b/servers/slapd/back-sql/delete.c @@ -1,8 +1,9 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2004 The OpenLDAP Foundation. + * Copyright 1999-2011 The OpenLDAP Foundation. * Portions Copyright 1999 Dmitry Kovalev. + * Portions Copyright 2002 Pierangelo Masarati. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,13 +16,12 @@ */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. + * by OpenLDAP Software. Additional significant contributors include + * Pierangelo Masarati. */ #include "portable.h" -#ifdef SLAPD_SQL - #include #include #include "ac/string.h" @@ -58,8 +58,7 @@ backsql_delete_all_attrs( Operation *op, SlapReply *rs, SQLHDBC dbh, - backsql_entryID *e_id, - backsql_oc_map_rec *oc ) + backsql_entryID *eid ) { backsql_delete_attr_t bda; int rc; @@ -67,9 +66,9 @@ backsql_delete_all_attrs( bda.op = op; bda.rs = rs; bda.dbh = dbh; - bda.e_id = e_id; + bda.e_id = eid; - rc = avl_apply( oc->bom_attrs, backsql_delete_attr_f, &bda, + rc = avl_apply( eid->eid_oc->bom_attrs, backsql_delete_attr_f, &bda, BACKSQL_AVL_STOP, AVL_INORDER ); if ( rc == BACKSQL_AVL_STOP ) { return rs->sr_err; @@ -78,98 +77,31 @@ backsql_delete_all_attrs( return LDAP_SUCCESS; } -int -backsql_delete( Operation *op, SlapReply *rs ) +static int +backsql_delete_int( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + SQLHSTMT *sthp, + backsql_entryID *eid, + Entry **ep ) { backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh; - SQLHSTMT sth; + SQLHSTMT sth = SQL_NULL_HSTMT; RETCODE rc; - int retval; - backsql_oc_map_rec *oc = NULL; - backsql_entryID e_id = BACKSQL_ENTRYID_INIT; - Entry e; + int prc = LDAP_SUCCESS; /* first parameter no */ - SQLUSMALLINT pno; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", - op->o_req_ndn.bv_val, 0, 0 ); - - dnParent( &op->o_req_dn, &e.e_name ); - dnParent( &op->o_req_ndn, &e.e_nname ); - e.e_attrs = NULL; - - /* check parent for "children" acl */ - if ( !access_allowed( op, &e, slap_schema.si_ad_children, - NULL, ACL_WRITE, NULL ) ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "no write access to parent\n", - 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto done; - - } - - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - goto done; - } - - rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "could not lookup entry id\n", 0, 0, 0 ); - goto done; - } - - rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn ); - switch ( rs->sr_err ) { - case LDAP_COMPARE_TRUE: - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "entry \"%s\" has children\n", - op->o_req_dn.bv_val, 0, 0 ); - rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; - rs->sr_text = "subtree delete not supported"; - goto done; - - case LDAP_COMPARE_FALSE: - break; - - default: - goto done; - } - - oc = backsql_id2oc( bi, e_id.eid_oc_id ); - if ( oc == NULL ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "cannot determine objectclass of entry -- aborting\n", - 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - goto done; - } + SQLUSMALLINT pno = 0; - if ( oc->bom_delete_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "delete procedure is not defined " - "for this objectclass - aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - goto done; - } + sth = *sthp; /* avl_apply ... */ - rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, &e_id, oc ); + rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, eid ); if ( rs->sr_err != LDAP_SUCCESS ) { goto done; } - rc = backsql_Prepare( dbh, &sth, oc->bom_delete_proc, 0 ); + rc = backsql_Prepare( dbh, &sth, eid->eid_oc->bom_delete_proc, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " @@ -179,59 +111,72 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + *ep = NULL; goto done; } - if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) { + if ( BACKSQL_IS_DEL( eid->eid_oc->bom_expect_return ) ) { pno = 1; - rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &retval ); + rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding output parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + *ep = NULL; goto done; } - - } else { - pno = 0; } - rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &e_id.eid_keyval ); + rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &eid->eid_keyval ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding keyval parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + *ep = NULL; goto done; } rc = SQLExecute( sth ); - if ( rc != SQL_SUCCESS ) { + if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { + rs->sr_err = LDAP_SUCCESS; + + } else { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "delete_proc execution failed\n", 0, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); + "delete_proc execution failed (rc=%d, prc=%d)\n", + rc, prc, 0 ); + + + if ( prc != LDAP_SUCCESS ) { + /* SQL procedure executed fine + * but returned an error */ + rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); + + } else { + backsql_PrintErrors( bi->sql_db_env, dbh, + sth, rc ); + rs->sr_err = LDAP_OTHER; + } SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; goto done; } SQLFreeStmt( sth, SQL_DROP ); /* delete "auxiliary" objectClasses, if any... */ - rc = backsql_Prepare( dbh, &sth, bi->sql_delobjclasses_query, 0 ); + rc = backsql_Prepare( dbh, &sth, bi->sql_delobjclasses_stmt, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " @@ -241,22 +186,24 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + *ep = NULL; goto done; } - rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id ); + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " "error binding auxiliary objectClasses " "entry ID parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + *ep = NULL; goto done; } @@ -276,124 +223,415 @@ backsql_delete( Operation *op, SlapReply *rs ) SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + *ep = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); - /* delete referrals, if any... */ - rc = backsql_Prepare( dbh, &sth, bi->sql_delreferrals_query, 0 ); + /* delete entry... */ + rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_stmt, 0 ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "error preparing ldap_referrals delete query\n", + "error preparing ldap_entries delete query\n", 0, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + *ep = NULL; goto done; } - rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id ); + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &eid->eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "error binding referrals entry ID parameter " + "error binding entry ID parameter " "for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + eid->eid_oc->bom_oc->soc_cname.bv_val, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + *ep = NULL; goto done; } rc = SQLExecute( sth ); - switch ( rc ) { - case SQL_NO_DATA: - /* apparently there were no referrals - * for this entry... */ - case SQL_SUCCESS: - break; - - default: + if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "failed to delete record from ldap_referrals\n", + "failed to delete record from ldap_entries\n", 0, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + *ep = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); - /* delete entry... */ - rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_query, 0 ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_delete(): " - "error preparing ldap_entries delete query\n", - 0, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); + rs->sr_err = LDAP_SUCCESS; + *ep = NULL; - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; +done:; + *sthp = sth; + + return rs->sr_err; +} + +typedef struct backsql_tree_delete_t { + Operation *btd_op; + int btd_rc; + backsql_entryID *btd_eid; +} backsql_tree_delete_t; + +static int +backsql_tree_delete_search_cb( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + backsql_tree_delete_t *btd; + backsql_entryID *eid; + + btd = (backsql_tree_delete_t *)op->o_callback->sc_private; + + if ( !access_allowed( btd->btd_op, rs->sr_entry, + slap_schema.si_ad_entry, NULL, ACL_WDEL, NULL ) + || !access_allowed( btd->btd_op, rs->sr_entry, + slap_schema.si_ad_children, NULL, ACL_WDEL, NULL ) ) + { + btd->btd_rc = LDAP_INSUFFICIENT_ACCESS; + return rs->sr_err = LDAP_UNAVAILABLE; + } + + assert( rs->sr_entry != NULL ); + assert( rs->sr_entry->e_private != NULL ); + + eid = (backsql_entryID *)rs->sr_entry->e_private; + assert( eid->eid_oc != NULL ); + if ( eid->eid_oc == NULL || eid->eid_oc->bom_delete_proc == NULL ) { + btd->btd_rc = LDAP_UNWILLING_TO_PERFORM; + return rs->sr_err = LDAP_UNAVAILABLE; + } + + eid = backsql_entryID_dup( eid, op->o_tmpmemctx ); + eid->eid_next = btd->btd_eid; + btd->btd_eid = eid; + } + + return 0; +} + +static int +backsql_tree_delete( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + SQLHSTMT *sthp ) +{ + Operation op2 = *op; + slap_callback sc = { 0 }; + SlapReply rs2 = { REP_RESULT }; + backsql_tree_delete_t btd = { 0 }; + + int rc; + + /* + * - perform an internal subtree search as the rootdn + * - for each entry + * - check access + * - check objectClass and delete method(s) + * - for each entry + * - delete + * - if successful, commit + */ + + op2.o_tag = LDAP_REQ_SEARCH; + op2.o_protocol = LDAP_VERSION3; + + btd.btd_op = op; + sc.sc_private = &btd; + sc.sc_response = backsql_tree_delete_search_cb; + op2.o_callback = ≻ + + op2.o_dn = op->o_bd->be_rootdn; + op2.o_ndn = op->o_bd->be_rootndn; + + op2.o_managedsait = SLAP_CONTROL_CRITICAL; + + op2.ors_scope = LDAP_SCOPE_SUBTREE; + op2.ors_deref = LDAP_DEREF_NEVER; + op2.ors_slimit = SLAP_NO_LIMIT; + op2.ors_tlimit = SLAP_NO_LIMIT; + op2.ors_filter = (Filter *)slap_filter_objectClass_pres; + op2.ors_filterstr = *slap_filterstr_objectClass_pres; + op2.ors_attrs = slap_anlist_all_attributes; + op2.ors_attrsonly = 0; + + rc = op->o_bd->be_search( &op2, &rs2 ); + if ( rc != LDAP_SUCCESS ) { + rc = rs->sr_err = btd.btd_rc; + rs->sr_text = "subtree delete not possible"; + send_ldap_result( op, rs ); + goto clean; + } + + for ( ; btd.btd_eid != NULL; + btd.btd_eid = backsql_free_entryID( btd.btd_eid, + 1, op->o_tmpmemctx ) ) + { + Entry *e = (void *)0xbad; + rc = backsql_delete_int( op, rs, dbh, sthp, btd.btd_eid, &e ); + if ( rc != LDAP_SUCCESS ) { + break; + } + } + +clean:; + for ( ; btd.btd_eid != NULL; + btd.btd_eid = backsql_free_entryID( btd.btd_eid, + 1, op->o_tmpmemctx ) ) + ; + + return rc; +} + +int +backsql_delete( Operation *op, SlapReply *rs ) +{ + SQLHDBC dbh = SQL_NULL_HDBC; + SQLHSTMT sth = SQL_NULL_HSTMT; + backsql_oc_map_rec *oc = NULL; + backsql_srch_info bsi = { 0 }; + backsql_entryID e_id = { 0 }; + Entry d = { 0 }, p = { 0 }, *e = NULL; + struct berval pdn = BER_BVNULL; + int manageDSAit = get_manageDSAit( op ); + + Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", + op->o_req_ndn.bv_val, 0, 0 ); + + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + e = NULL; goto done; } - rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_delete(): " - "error binding entry ID parameter " - "for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbh, - sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); + /* + * Get the entry + */ + bsi.bsi_e = &d; + rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, + LDAP_SCOPE_BASE, + (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + break; - rs->sr_text = "SQL-backend error"; - rs->sr_err = LDAP_OTHER; + case LDAP_REFERRAL: + if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && + dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) + { + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + break; + } + e = &d; + /* fallthru */ + + default: + Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " + "could not retrieve deleteDN ID - no such entry\n", + 0, 0, 0 ); + if ( !BER_BVISNULL( &d.e_nname ) ) { + /* FIXME: should always be true! */ + e = &d; + + } else { + e = NULL; + } goto done; } - rc = SQLExecute( sth ); - if ( rc != SQL_SUCCESS ) { + if ( get_assert( op ) && + ( test_filter( op, &d, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = &d; + goto done; + } + + if ( !access_allowed( op, &d, slap_schema.si_ad_entry, + NULL, ACL_WDEL, NULL ) ) + { Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " - "failed to delete record from ldap_entries\n", + "no write access to entry\n", 0, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + e = &d; + goto done; + } + + rs->sr_err = backsql_has_children( op, dbh, &op->o_req_ndn ); + switch ( rs->sr_err ) { + case LDAP_COMPARE_FALSE: + rs->sr_err = LDAP_SUCCESS; + break; + + case LDAP_COMPARE_TRUE: +#ifdef SLAP_CONTROL_X_TREE_DELETE + if ( get_treeDelete( op ) ) { + rs->sr_err = LDAP_SUCCESS; + break; + } +#endif /* SLAP_CONTROL_X_TREE_DELETE */ + + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "entry \"%s\" has children\n", + op->o_req_dn.bv_val, 0, 0 ); + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subordinate objects must be deleted first"; + /* fallthru */ + + default: + e = &d; + goto done; + } + + assert( bsi.bsi_base_id.eid_oc != NULL ); + oc = bsi.bsi_base_id.eid_oc; + if ( oc->bom_delete_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "delete procedure is not defined " + "for this objectclass - aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + e = NULL; goto done; } - SQLFreeStmt( sth, SQL_DROP ); + + /* + * Get the parent + */ + e_id = bsi.bsi_base_id; + memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); + if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) { + dnParent( &op->o_req_ndn, &pdn ); + bsi.bsi_e = &p; + rs->sr_err = backsql_init_search( &bsi, &pdn, + LDAP_SCOPE_BASE, + (time_t)(-1), NULL, dbh, op, rs, + slap_anlist_no_attrs, + BACKSQL_ISF_GET_ENTRY ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " + "could not retrieve deleteDN ID " + "- no such entry\n", + 0, 0, 0 ); + e = &p; + goto done; + } + + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); + + /* check parent for "children" acl */ + if ( !access_allowed( op, &p, slap_schema.si_ad_children, + NULL, ACL_WDEL, NULL ) ) + { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "no write access to parent\n", + 0, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + e = &p; + goto done; + + } + } + + e = &d; +#ifdef SLAP_CONTROL_X_TREE_DELETE + if ( get_treeDelete( op ) ) { + backsql_tree_delete( op, rs, dbh, &sth ); + if ( rs->sr_err == LDAP_OTHER || rs->sr_err == LDAP_SUCCESS ) + { + e = NULL; + } + + } else +#endif /* SLAP_CONTROL_X_TREE_DELETE */ + { + backsql_delete_int( op, rs, dbh, &sth, &e_id, &e ); + } /* * Commit only if all operations succeed - * - * FIXME: backsql_add() does not fail if add operations - * are not available for some attributes, or if - * a multiple value add actually results in a replace, - * or if a single operation on an attribute fails - * for any reason */ - SQLTransact( SQL_NULL_HENV, dbh, - op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); + if ( sth != SQL_NULL_HSTMT ) { + SQLUSMALLINT CompletionType = SQL_ROLLBACK; + + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + assert( e == NULL ); + CompletionType = SQL_COMMIT; + } - rs->sr_err = LDAP_SUCCESS; + SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); + } done:; + if ( e != NULL ) { + if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, + ACL_DISCLOSE, NULL ) ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + } + } + + if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { + rs->sr_err = LDAP_X_NO_OPERATION; + } + send_ldap_result( op, rs ); Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 ); - return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 ); -} + if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { + (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); + } -#endif /* SLAPD_SQL */ + if ( !BER_BVISNULL( &d.e_nname ) ) { + backsql_entry_clean( op, &d ); + } + + if ( !BER_BVISNULL( &p.e_nname ) ) { + backsql_entry_clean( op, &p ); + } + + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + + return rs->sr_err; +}