2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2004 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
17 * This work was initially developed by Dmitry Kovalev for inclusion
18 * by OpenLDAP Software.
26 #include <sys/types.h>
27 #include "ac/string.h"
32 #include "schema-map.h"
37 * PostgreSQL 7.0 doesn't work without :(
39 #define BACKSQL_REALLOC_STMT
43 * - the first occurrence of objectClass, which is used
44 * to determine how to build the SQL entry (FIXME ?!?)
45 * - operational attributes
46 * empty attributes (FIXME ?!?)
48 #define backsql_attr_skip(ad,vals) \
50 ( (ad) == slap_schema.si_ad_objectClass \
51 && (vals)[ 1 ].bv_val == NULL ) \
52 || is_at_operational( (ad)->ad_type ) \
53 || ( (vals)[ 0 ].bv_val == NULL ) \
57 backsql_modify_internal(
61 backsql_oc_map_rec *oc,
62 backsql_entryID *e_id,
63 Modifications *modlist )
65 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
70 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
71 "traversing modifications list\n", 0, 0, 0 );
73 #ifndef BACKSQL_REALLOC_STMT
74 SQLAllocStmt( dbh, &sth );
75 #endif /* BACKSQL_REALLOC_STMT */
77 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
78 AttributeDescription *ad;
79 backsql_at_map_rec *at = NULL;
80 struct berval *at_val;
83 /* first parameter no, parameter order */
85 /* procedure return code */
88 #ifdef BACKSQL_REALLOC_STMT
89 SQLAllocStmt( dbh, &sth );
90 #endif /* BACKSQL_REALLOC_STMT */
95 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
96 "modifying attribute '%s'\n",
97 ad->ad_cname.bv_val, 0, 0 );
99 if ( backsql_attr_skip( ad, c_mod->sm_bvalues ) ) {
103 at = backsql_ad2at( oc, ad );
105 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
106 "attribute provided is not registered "
107 "in objectClass '%s'\n",
108 ad->ad_cname.bv_val, 0, 0 );
110 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
111 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
112 rs->sr_text = "operation not permitted "
113 "within namingContext";
120 switch( c_mod->sm_op ) {
121 case LDAP_MOD_REPLACE: {
125 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
126 "replacing values for attribute '%s'\n",
127 at->bam_ad->ad_cname.bv_val, 0, 0 );
129 if ( at->bam_add_proc == NULL ) {
130 Debug( LDAP_DEBUG_TRACE,
131 "backsql_modify_internal(): "
132 "add procedure is not defined "
133 "for attribute '%s' "
134 "- unable to perform replacements\n",
135 at->bam_ad->ad_cname.bv_val, 0, 0 );
137 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
138 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
139 rs->sr_text = "operation not permitted "
140 "within namingContext";
147 if ( at->bam_delete_proc == NULL ) {
148 Debug( LDAP_DEBUG_TRACE,
149 "backsql_modify_internal(): "
150 "delete procedure is not defined "
151 "for attribute '%s' "
153 at->bam_ad->ad_cname.bv_val, 0, 0 );
155 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
156 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
157 rs->sr_text = "operation not permitted "
158 "within namingContext";
166 rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
167 if ( rc != SQL_SUCCESS ) {
168 Debug( LDAP_DEBUG_TRACE,
169 "backsql_modify_internal(): "
170 "error preparing query\n", 0, 0, 0 );
171 backsql_PrintErrors( bi->db_env, dbh,
174 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
175 rs->sr_err = LDAP_OTHER;
176 rs->sr_text = "SQL-backend error";
183 rc = backsql_BindParamID( asth, 1, &e_id->keyval );
184 if ( rc != SQL_SUCCESS ) {
185 Debug( LDAP_DEBUG_TRACE,
186 "backsql_modify_internal(): "
187 "error binding key value parameter\n",
189 backsql_PrintErrors( bi->db_env, dbh,
191 SQLFreeStmt( asth, SQL_DROP );
193 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
194 rs->sr_err = LDAP_OTHER;
195 rs->sr_text = "SQL-backend error";
202 rc = SQLExecute( asth );
203 if ( !BACKSQL_SUCCESS( rc ) ) {
204 Debug( LDAP_DEBUG_TRACE,
205 "backsql_modify_internal(): "
206 "error executing attribute query\n",
208 backsql_PrintErrors( bi->db_env, dbh,
210 SQLFreeStmt( asth, SQL_DROP );
212 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
213 rs->sr_err = LDAP_OTHER;
214 rs->sr_text = "SQL-backend error";
221 backsql_BindRowAsStrings( asth, &row );
222 rc = SQLFetch( asth );
223 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
224 for ( i = 0; i < row.ncols; i++ ) {
225 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
227 SQLBindParameter(sth, 1,
235 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
236 SQLBindParameter( sth, pno + 1 + po,
238 SQL_C_ULONG, SQL_INTEGER,
239 0, 0, &e_id->keyval, 0, 0 );
242 * check for syntax needed here
243 * maybe need binary bind?
245 SQLBindParameter(sth, pno + 2 - po,
247 SQL_C_CHAR, SQL_CHAR,
249 strlen( row.cols[ i ] ), 0 );
251 Debug( LDAP_DEBUG_TRACE,
252 "backsql_modify_internal(): "
254 at->bam_delete_proc, 0, 0 );
255 rc = SQLExecDirect( sth,
256 at->bam_delete_proc, SQL_NTS );
257 if ( rc != SQL_SUCCESS ) {
258 Debug( LDAP_DEBUG_TRACE,
259 "backsql_modify_internal(): "
261 "execution failed\n",
263 backsql_PrintErrors( bi->db_env,
266 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
267 rs->sr_err = LDAP_OTHER;
268 rs->sr_text = "SQL-backend error";
272 #ifdef BACKSQL_REALLOC_STMT
273 SQLFreeStmt( sth, SQL_DROP );
274 SQLAllocStmt( dbh, &sth );
275 #endif /* BACKSQL_REALLOC_STMT */
278 backsql_FreeRow( &row );
279 SQLFreeStmt( asth, SQL_DROP );
283 * PASSTHROUGH - to add new attributes -- do NOT add break
286 case SLAP_MOD_SOFTADD:
288 if ( at->bam_add_proc == NULL ) {
289 Debug( LDAP_DEBUG_TRACE,
290 "backsql_modify_internal(): "
291 "add procedure is not defined "
292 "for attribute '%s'\n",
293 at->bam_ad->ad_cname.bv_val, 0, 0 );
295 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
296 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
297 rs->sr_text = "operation not permitted "
298 "within namingContext";
305 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
306 "adding new values for attribute '%s'\n",
307 at->bam_ad->ad_cname.bv_val, 0, 0 );
308 for ( i = 0, at_val = c_mod->sm_bvalues;
309 at_val->bv_val != NULL;
311 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
313 SQLBindParameter( sth, 1,
315 SQL_C_ULONG, SQL_INTEGER,
320 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
321 SQLBindParameter( sth, pno + 1 + po,
323 SQL_C_ULONG, SQL_INTEGER,
324 0, 0, &e_id->keyval, 0, 0 );
327 * check for syntax needed here
328 * maybe need binary bind?
330 SQLBindParameter( sth, pno + 2 - po,
332 SQL_C_CHAR, SQL_CHAR,
333 0, 0, at_val->bv_val,
336 Debug( LDAP_DEBUG_TRACE,
337 "backsql_modify_internal(): "
339 at->bam_add_proc, 0, 0 );
340 rc = SQLExecDirect( sth, at->bam_add_proc,
342 if ( rc != SQL_SUCCESS ) {
343 Debug( LDAP_DEBUG_TRACE,
344 "backsql_modify_internal(): "
345 "add_proc execution failed\n",
347 backsql_PrintErrors( bi->db_env,
350 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
351 rs->sr_err = LDAP_OTHER;
352 rs->sr_text = "SQL-backend error";
356 #ifdef BACKSQL_REALLOC_STMT
357 SQLFreeStmt( sth, SQL_DROP );
358 SQLAllocStmt( dbh, &sth );
359 #endif /* BACKSQL_REALLOC_STMT */
363 case LDAP_MOD_DELETE:
364 if ( at->bam_delete_proc == NULL ) {
365 Debug( LDAP_DEBUG_TRACE,
366 "backsql_modify_internal(): "
367 "delete procedure is not defined "
368 "for attribute '%s'\n",
369 at->bam_ad->ad_cname.bv_val, 0, 0 );
371 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
372 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
373 rs->sr_text = "operation not permitted "
374 "within namingContext";
381 if ( c_mod->sm_bvalues == NULL ) {
382 Debug( LDAP_DEBUG_TRACE,
383 "backsql_modify_internal(): "
384 "no values given to delete "
385 "for attribute '%s' "
386 "-- deleting all values\n",
387 at->bam_ad->ad_cname.bv_val, 0, 0 );
391 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
392 "deleting values for attribute '%s'\n",
393 at->bam_ad->ad_cname.bv_val, 0, 0 );
395 for ( i = 0, at_val = c_mod->sm_bvalues;
396 at_val->bv_val != NULL;
398 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
400 SQLBindParameter( sth, 1,
402 SQL_C_ULONG, SQL_INTEGER,
407 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
408 SQLBindParameter( sth, pno + 1 + po,
410 SQL_C_ULONG, SQL_INTEGER,
411 0, 0, &e_id->keyval, 0, 0 );
414 * check for syntax needed here
415 * maybe need binary bind?
417 SQLBindParameter( sth, pno + 2 - po,
418 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
419 0, 0, at_val->bv_val,
422 Debug( LDAP_DEBUG_TRACE,
423 "backsql_modify_internal(): "
425 at->bam_delete_proc, 0, 0 );
426 rc = SQLExecDirect( sth, at->bam_delete_proc,
428 if ( rc != SQL_SUCCESS ) {
429 Debug( LDAP_DEBUG_TRACE,
430 "backsql_modify_internal(): "
431 "delete_proc execution "
432 "failed\n", 0, 0, 0 );
433 backsql_PrintErrors( bi->db_env,
436 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
437 rs->sr_err = LDAP_OTHER;
438 rs->sr_text = "SQL-backend error";
442 #ifdef BACKSQL_REALLOC_STMT
443 SQLFreeStmt( sth, SQL_DROP );
444 SQLAllocStmt( dbh, &sth );
445 #endif /* BACKSQL_REALLOC_STMT */
449 #ifndef BACKSQL_REALLOC_STMT
450 SQLFreeStmt( sth, SQL_RESET_PARAMS );
451 #else /* BACKSQL_REALLOC_STMT */
452 SQLFreeStmt( sth, SQL_DROP );
453 #endif /* BACKSQL_REALLOC_STMT */
458 #ifndef BACKSQL_REALLOC_STMT
459 SQLFreeStmt( sth, SQL_DROP );
460 #endif /* BACKSQL_REALLOC_STMT */
463 * FIXME: should fail in case one change fails?
469 backsql_modify( Operation *op, SlapReply *rs )
471 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
473 backsql_oc_map_rec *oc = NULL;
474 backsql_entryID e_id;
478 * FIXME: in case part of the operation cannot be performed
479 * (missing mapping, SQL write fails or so) the entire operation
480 * should be rolled-back
482 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
483 op->o_req_ndn.bv_val, 0, 0 );
485 rs->sr_err = backsql_get_db_conn( op, &dbh );
486 if ( rs->sr_err != LDAP_SUCCESS ) {
487 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
488 "could not get connection handle - exiting\n",
491 * FIXME: we don't want to send back
492 * excessively detailed messages
494 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
495 ? "SQL-backend error" : NULL;
496 send_ldap_result( op, rs );
500 rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn );
501 if ( rs->sr_err != LDAP_SUCCESS ) {
502 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
503 "could not lookup entry id\n", 0, 0, 0 );
504 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
505 ? "SQL-backend error" : NULL;
506 send_ldap_result( op, rs );
510 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
511 "modifying entry '%s' (id=%ld)\n",
512 e_id.dn.bv_val, e_id.id, 0 );
514 oc = backsql_id2oc( bi, e_id.oc_id );
516 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
517 "cannot determine objectclass of entry -- aborting\n",
520 * FIXME: should never occur, since the entry was built!!!
524 * FIXME: we don't want to send back
525 * excessively detailed messages
527 rs->sr_err = LDAP_OTHER;
528 rs->sr_text = "SQL-backend error";
529 send_ldap_result( op, rs );
534 e.e_name = op->o_req_dn;
535 e.e_nname = op->o_req_ndn;
536 if ( !acl_check_modlist( op, &e, op->oq_modify.rs_modlist ) ) {
537 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
540 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id,
541 op->oq_modify.rs_modlist );
544 if ( rs->sr_err == LDAP_SUCCESS ) {
546 * Commit only if all operations succeed
548 SQLTransact( SQL_NULL_HENV, dbh,
549 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
551 send_ldap_result( op, rs );
552 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
558 backsql_modrdn( Operation *op, SlapReply *rs )
560 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
564 backsql_entryID e_id, pe_id, new_pid;
565 backsql_oc_map_rec *oc = NULL;
566 struct berval p_dn, p_ndn,
567 *new_pdn = NULL, *new_npdn = NULL,
569 LDAPRDN new_rdn = NULL;
570 LDAPRDN old_rdn = NULL;
573 struct berval *newSuperior = op->oq_modrdn.rs_newSup;
575 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
576 "newrdn='%s', newSuperior='%s'\n",
577 op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val,
578 newSuperior ? newSuperior->bv_val : "(NULL)" );
579 rs->sr_err = backsql_get_db_conn( op, &dbh );
580 if ( rs->sr_err != LDAP_SUCCESS ) {
581 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
582 "could not get connection handle - exiting\n",
584 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
585 ? "SQL-backend error" : NULL;
586 send_ldap_result( op, rs );
590 rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn );
591 if ( rs->sr_err != LDAP_SUCCESS ) {
592 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
593 "could not lookup entry id\n", 0, 0, 0 );
594 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
595 ? "SQL-backend error" : NULL;
596 send_ldap_result( op, rs );
600 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
603 if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
604 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
605 "entry \"%s\" has children\n",
606 op->o_req_dn.bv_val, 0, 0 );
607 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
608 rs->sr_text = "subtree rename not supported";
609 send_ldap_result( op, rs );
613 dnParent( &op->o_req_dn, &p_dn );
614 dnParent( &op->o_req_ndn, &p_ndn );
617 * namingContext "" is not supported
619 if ( p_dn.bv_len == 0 ) {
620 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
621 "parent is \"\" - aborting\n", 0, 0, 0 );
622 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
623 rs->sr_text = "not allowed within namingContext";
624 send_ldap_result( op, rs );
629 * Check for children access to parent
634 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
635 NULL, ACL_WRITE, NULL ) ) {
636 Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
637 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
643 * namingContext "" is not supported
645 if ( newSuperior->bv_len == 0 ) {
646 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
647 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
648 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
649 rs->sr_text = "not allowed within namingContext";
650 send_ldap_result( op, rs );
654 new_pdn = newSuperior;
655 new_npdn = op->oq_modrdn.rs_nnewSup;
658 e.e_nname = *new_npdn;
661 * Check for children access to new parent
663 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
664 NULL, ACL_WRITE, NULL ) ) {
665 Debug( LDAP_DEBUG_TRACE, "no access to new parent\n",
667 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
676 if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
677 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
678 "newSuperior is equal to old parent - ignored\n",
683 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
684 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
685 "newSuperior is equal to entry being moved "
686 "- aborting\n", 0, 0, 0 );
687 rs->sr_err = LDAP_OTHER;
688 rs->sr_text = "newSuperior is equal to old DN";
689 send_ldap_result( op, rs );
693 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, NULL );
694 rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
696 if ( rs->sr_err != LDAP_SUCCESS ) {
697 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
698 "new dn is invalid ('%s') - aborting\n",
699 new_dn.bv_val, 0, 0 );
700 rs->sr_text = "unable to build new DN";
701 send_ldap_result( op, rs );
705 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): new entry dn is '%s'\n",
706 new_dn.bv_val, 0, 0 );
708 rs->sr_err = backsql_dn2id( bi, &pe_id, dbh, &p_ndn );
709 if ( rs->sr_err != LDAP_SUCCESS ) {
710 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
711 "could not lookup old parent entry id\n", 0, 0, 0 );
712 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
713 ? "SQL-backend error" : NULL;
714 send_ldap_result( op, rs );
718 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
719 "old parent entry id is %ld\n", pe_id.id, 0, 0 );
721 rs->sr_err = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
722 if ( rs->sr_err != LDAP_SUCCESS ) {
723 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
724 "could not lookup new parent entry id\n", 0, 0, 0 );
725 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
726 ? "SQL-backend error" : NULL;
727 send_ldap_result( op, rs );
731 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
732 "new parent entry id is %ld\n", new_pid.id, 0, 0 );
735 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
736 "executing delentry_query\n", 0, 0, 0 );
737 SQLAllocStmt( dbh, &sth );
738 SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
739 0, 0, &e_id.id, 0, 0 );
740 rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
741 if ( rc != SQL_SUCCESS ) {
742 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
743 "failed to delete record from ldap_entries\n",
745 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
746 rs->sr_err = LDAP_OTHER;
747 rs->sr_text = "SQL-backend error";
748 send_ldap_result( op, rs );
752 SQLFreeStmt( sth, SQL_RESET_PARAMS );
754 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
755 "executing insentry_query\n", 0, 0, 0 );
756 backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
757 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
758 0, 0, &e_id.oc_id, 0, 0 );
759 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
760 0, 0, &new_pid.id, 0, 0 );
761 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
762 0, 0, &e_id.keyval, 0, 0 );
763 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
764 if ( rc != SQL_SUCCESS ) {
765 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
766 "could not insert ldap_entries record\n", 0, 0, 0 );
767 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
768 rs->sr_err = LDAP_OTHER;
769 rs->sr_text = "SQL-backend error";
770 send_ldap_result( op, rs );
775 * Get attribute type and attribute value of our new rdn,
776 * we will need to add that to our new entry
778 if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn,
779 (char **)&rs->sr_text,
780 LDAP_DN_FORMAT_LDAP ) ) {
782 LDAP_LOG ( OPERATION, ERR,
783 "backsql_modrdn: can't figure out "
784 "type(s)/values(s) of newrdn\n",
787 Debug( LDAP_DEBUG_TRACE,
788 "backsql_modrdn: can't figure out "
789 "type(s)/values(s) of newrdn\n",
792 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
797 LDAP_LOG ( OPERATION, RESULTS,
798 "backsql_modrdn: new_rdn_type=\"%s\", "
799 "new_rdn_val=\"%s\"\n",
800 new_rdn[ 0 ]->la_attr.bv_val,
801 new_rdn[ 0 ]->la_value.bv_val, 0 );
803 Debug( LDAP_DEBUG_TRACE,
804 "backsql_modrdn: new_rdn_type=\"%s\", "
805 "new_rdn_val=\"%s\"\n",
806 new_rdn[ 0 ]->la_attr.bv_val,
807 new_rdn[ 0 ]->la_value.bv_val, 0 );
810 if ( op->oq_modrdn.rs_deleteoldrdn ) {
811 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn,
812 (char **)&rs->sr_text,
813 LDAP_DN_FORMAT_LDAP ) ) {
815 LDAP_LOG ( OPERATION, ERR,
816 "backsql_modrdn: can't figure out "
817 "type(s)/values(s) of old_rdn\n",
820 Debug( LDAP_DEBUG_TRACE,
821 "backsql_modrdn: can't figure out "
822 "the old_rdn type(s)/value(s)\n",
825 rs->sr_err = LDAP_OTHER;
832 rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod );
833 if ( rs->sr_err != LDAP_SUCCESS ) {
837 if ( !acl_check_modlist( op, &e, mod )) {
838 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
842 oc = backsql_id2oc( bi, e_id.oc_id );
843 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
845 if ( rs->sr_err == LDAP_SUCCESS ) {
848 * Commit only if all operations succeed
850 SQLTransact( SQL_NULL_HENV, dbh,
851 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
855 SQLFreeStmt( sth, SQL_DROP );
857 if ( new_dn.bv_val ) {
858 ch_free( new_dn.bv_val );
861 if ( new_ndn.bv_val ) {
862 ch_free( new_ndn.bv_val );
865 /* LDAP v2 supporting correct attribute handling. */
866 if ( new_rdn != NULL ) {
867 ldap_rdnfree( new_rdn );
869 if ( old_rdn != NULL ) {
870 ldap_rdnfree( old_rdn );
874 for (; mod; mod=tmp ) {
880 send_ldap_result( op, rs );
882 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
887 backsql_add( Operation *op, SlapReply *rs )
889 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
892 unsigned long new_keyval = 0;
895 backsql_oc_map_rec *oc = NULL;
896 backsql_at_map_rec *at_rec = NULL;
897 backsql_entryID e_id, parent_id;
900 struct berval *at_val;
902 /* first parameter #, parameter order */
903 SQLUSMALLINT pno, po;
904 /* procedure return code */
907 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n",
908 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
911 if ( global_schemacheck ) {
912 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
914 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
916 &rs->sr_text, textbuf, sizeof( textbuf ) );
917 if ( rs->sr_err != LDAP_SUCCESS ) {
918 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
919 "entry failed schema check -- aborting\n",
921 send_ldap_result( op, rs );
926 /* search structural objectClass */
927 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
928 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
933 /* there must exist */
934 assert( at != NULL );
936 /* I guess we should play with sub/supertypes to find a suitable oc */
937 oc = backsql_name2oc( bi, &at->a_vals[0] );
940 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
941 "cannot determine objectclass of entry -- aborting\n",
943 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
944 rs->sr_text = "operation not permitted within namingContext";
945 send_ldap_result( op, rs );
949 if ( oc->bom_create_proc == NULL ) {
950 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
951 "create procedure is not defined for this objectclass "
952 "- aborting\n", 0, 0, 0 );
953 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
954 rs->sr_text = "operation not permitted within namingContext";
955 send_ldap_result( op, rs );
958 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
959 && oc->bom_create_keyval == NULL ) {
960 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
961 "create procedure needs select procedure, "
962 "but none is defined - aborting\n", 0, 0, 0 );
963 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
964 rs->sr_text = "operation not permitted within namingContext";
965 send_ldap_result( op, rs );
969 rs->sr_err = backsql_get_db_conn( op, &dbh );
970 if ( rs->sr_err != LDAP_SUCCESS ) {
971 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
972 "could not get connection handle - exiting\n",
974 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
975 ? "SQL-backend error" : NULL,
976 send_ldap_result( op, rs );
981 * Check if entry exists
983 rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->oq_add.rs_e->e_name );
984 if ( rs->sr_err == LDAP_SUCCESS ) {
985 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
986 "entry '%s' exists\n",
987 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
988 rs->sr_err = LDAP_ALREADY_EXISTS;
989 send_ldap_result( op, rs );
994 * Check if parent exists
996 dnParent( &op->oq_add.rs_e->e_name, &pdn );
997 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
998 if ( rs->sr_err != LDAP_SUCCESS ) {
999 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1000 "could not lookup parent entry for new record '%s'\n",
1003 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1004 send_ldap_result( op, rs );
1013 char *matched = NULL;
1016 dnParent( &dn, &pdn );
1019 * Empty DN ("") defaults to LDAP_SUCCESS
1021 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
1022 switch ( rs->sr_err ) {
1023 case LDAP_NO_SUCH_OBJECT:
1024 if ( pdn.bv_len > 0 ) {
1027 /* fail over to next case */
1030 matched = pdn.bv_val;
1031 /* fail over to next case */
1034 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1035 rs->sr_matched = matched;
1036 send_ldap_result( op, rs );
1043 * create_proc is executed; if expect_return is set, then
1044 * an output parameter is bound, which should contain
1045 * the id of the added row; otherwise the procedure
1046 * is expected to return the id as the first column of a select
1051 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
1052 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
1053 NULL, ACL_WRITE, NULL ) ) {
1054 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1055 send_ldap_result( op, rs );
1059 rc = SQLAllocStmt( dbh, &sth );
1060 if ( rc != SQL_SUCCESS ) {
1061 rs->sr_err = LDAP_OTHER;
1062 rs->sr_text = "SQL-backend error";
1063 send_ldap_result( op, rs );
1067 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1068 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1069 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1072 Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s'\n",
1073 oc->bom_create_proc, 0, 0 );
1074 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
1075 if ( rc != SQL_SUCCESS ) {
1076 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1077 "create_proc execution failed\n", 0, 0, 0 );
1078 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1079 SQLFreeStmt( sth, SQL_DROP );
1080 rs->sr_err = LDAP_OTHER;
1081 rs->sr_text = "SQL-backend error";
1082 send_ldap_result( op, rs );
1086 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1089 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1091 SQLINTEGER value_len;
1093 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1094 #ifndef BACKSQL_REALLOC_STMT
1095 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1096 #else /* BACKSQL_REALLOC_STMT */
1097 SQLFreeStmt( sth, SQL_DROP );
1098 rc = SQLAllocStmt( dbh, &sth );
1099 if ( rc != SQL_SUCCESS ) {
1100 rs->sr_err = LDAP_OTHER;
1101 rs->sr_text = "SQL-backend error";
1102 send_ldap_result( op, rs );
1105 #endif /* BACKSQL_REALLOC_STMT */
1107 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
1108 if ( rc != SQL_SUCCESS ) {
1109 rs->sr_err = LDAP_OTHER;
1110 rs->sr_text = "SQL-backend error";
1111 send_ldap_result( op, rs );
1117 * the query to know the id of the inserted entry
1118 * must be embedded in the create procedure
1120 rc = SQLNumResultCols( sth, &ncols );
1121 if ( rc != SQL_SUCCESS ) {
1122 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1123 "create_proc result evaluation failed\n",
1125 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1126 SQLFreeStmt( sth, SQL_DROP );
1127 rs->sr_err = LDAP_OTHER;
1128 rs->sr_text = "SQL-backend error";
1129 send_ldap_result( op, rs );
1132 } else if ( ncols != 1 ) {
1133 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1134 "create_proc result is bogus (ncols=%d)\n",
1136 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1137 SQLFreeStmt( sth, SQL_DROP );
1138 rs->sr_err = LDAP_OTHER;
1139 rs->sr_text = "SQL-backend error";
1140 send_ldap_result( op, rs );
1146 SQLCHAR colname[ 64 ];
1147 SQLSMALLINT name_len, col_type, col_scale, col_null;
1151 * FIXME: check whether col_type is compatible,
1152 * if it can be null and so on ...
1154 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
1156 (SQLUINTEGER)( sizeof( colname ) - 1 ),
1157 &name_len, &col_type,
1158 &col_prec, &col_scale, &col_null );
1162 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1163 (SQLPOINTER)&new_keyval,
1164 (SQLINTEGER)sizeof( new_keyval ),
1167 rc = SQLFetch( sth );
1169 if ( value_len <= 0 ) {
1170 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1171 "create_proc result is empty?\n",
1173 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1174 SQLFreeStmt( sth, SQL_DROP );
1175 rs->sr_err = LDAP_OTHER;
1176 rs->sr_text = "SQL-backend error";
1177 send_ldap_result( op, rs );
1182 #ifndef BACKSQL_REALLOC_STMT
1183 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1184 #else /* BACKSQL_REALLOC_STMT */
1185 SQLFreeStmt( sth, SQL_DROP );
1186 #endif /* BACKSQL_REALLOC_STMT */
1188 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1189 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
1191 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
1192 SQLUSMALLINT currpos;
1194 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1195 "adding attribute '%s'\n",
1196 at->a_desc->ad_cname.bv_val, 0, 0 );
1200 * - the first occurrence of objectClass, which is used
1201 * to determine how to bulid the SQL entry (FIXME ?!?)
1202 * - operational attributes
1203 * empty attributes (FIXME ?!?)
1205 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1209 at_rec = backsql_ad2at( oc, at->a_desc );
1211 if ( at_rec == NULL ) {
1212 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1213 "attribute '%s' is not registered "
1214 "in objectclass '%s'\n",
1215 at->a_desc->ad_cname.bv_val,
1216 BACKSQL_OC_NAME( oc ), 0 );
1218 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1219 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1220 rs->sr_text = "operation not permitted "
1221 "within namingContext";
1222 send_ldap_result( op, rs );
1229 if ( at_rec->bam_add_proc == NULL ) {
1230 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1231 "add procedure is not defined "
1232 "for attribute '%s'\n",
1233 at->a_desc->ad_cname.bv_val, 0, 0 );
1235 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1236 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1237 rs->sr_text = "operation not permitted "
1238 "within namingContext";
1239 send_ldap_result( op, rs );
1246 #ifdef BACKSQL_REALLOC_STMT
1247 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
1248 if ( rc != SQL_SUCCESS ) {
1250 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1251 rs->sr_err = LDAP_OTHER;
1252 rs->sr_text = "SQL-backend error";
1253 send_ldap_result( op, rs );
1259 #endif /* BACKSQL_REALLOC_STMT */
1261 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
1263 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
1264 SQL_C_ULONG, SQL_INTEGER,
1270 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
1271 currpos = pno + 1 + po;
1272 SQLBindParameter( sth, currpos,
1273 SQL_PARAM_INPUT, SQL_C_ULONG,
1274 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1275 currpos = pno + 2 - po;
1277 for ( i = 0, at_val = &at->a_vals[ i ];
1278 at_val->bv_val != NULL;
1279 i++, at_val = &at->a_vals[ i ] ) {
1282 * Do not deal with the objectClass that is used
1283 * to build the entry
1285 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1286 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
1292 * check for syntax needed here
1293 * maybe need binary bind?
1296 backsql_BindParamStr( sth, currpos,
1297 at_val->bv_val, at_val->bv_len + 1 );
1298 #ifdef SECURITY_PARANOID
1299 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1300 "executing '%s', id=%ld\n",
1301 at_rec->bam_add_proc, new_keyval, 0 );
1303 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1304 "executing '%s' with val='%s', id=%ld\n",
1305 at_rec->bam_add_proc, at_val->bv_val, new_keyval );
1307 #ifndef BACKSQL_REALLOC_STMT
1308 rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
1309 #else /* BACKSQL_REALLOC_STMT */
1310 rc = SQLExecute( sth );
1311 #endif /* BACKSQL_REALLOC_STMT */
1312 if ( rc != SQL_SUCCESS ) {
1313 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1314 "add_proc execution failed\n",
1316 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1318 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1319 rs->sr_err = LDAP_OTHER;
1320 rs->sr_text = "SQL-backend error";
1321 send_ldap_result( op, rs );
1326 #ifndef BACKSQL_REALLOC_STMT
1327 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1328 #else /* BACKSQL_REALLOC_STMT */
1329 SQLFreeStmt( sth, SQL_DROP );
1330 #endif /* BACKSQL_REALLOC_STMT */
1333 #ifdef BACKSQL_REALLOC_STMT
1334 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1335 if ( rc != SQL_SUCCESS ) {
1336 rs->sr_err = LDAP_OTHER;
1337 rs->sr_text = "SQL-backend error";
1338 send_ldap_result( op, rs );
1341 #endif /* BACKSQL_REALLOC_STMT */
1343 backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
1344 BACKSQL_MAX_DN_LEN );
1345 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1346 0, 0, &oc->bom_id, 0, 0 );
1347 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1348 0, 0, &parent_id.id, 0, 0 );
1349 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1350 0, 0, &new_keyval, 0, 0 );
1352 Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s' for dn '%s'\n",
1353 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1354 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, "
1355 "keyval=%ld\n", oc->bom_id, parent_id.id, new_keyval );
1356 #ifndef BACKSQL_REALLOC_STMT
1357 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1358 #else /* BACKSQL_REALLOC_STMT */
1359 rc = SQLExecute( sth );
1360 #endif /* BACKSQL_REALLOC_STMT */
1361 if ( rc != SQL_SUCCESS ) {
1362 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1363 "could not insert ldap_entries record\n", 0, 0, 0 );
1364 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1367 * execute delete_proc to delete data added !!!
1369 SQLFreeStmt( sth, SQL_DROP );
1370 rs->sr_err = LDAP_OTHER;
1371 rs->sr_text = "SQL-backend error";
1372 send_ldap_result( op, rs );
1376 SQLFreeStmt( sth, SQL_DROP );
1379 * Commit only if all operations succeed
1381 SQLTransact( SQL_NULL_HENV, dbh,
1382 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1385 * FIXME: NOOP does not work for add -- it works for all
1386 * the other operations, and I don't get the reason :(
1389 send_ldap_result( op, rs );
1395 backsql_delete( Operation *op, SlapReply *rs )
1397 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
1401 backsql_oc_map_rec *oc = NULL;
1402 backsql_entryID e_id;
1404 /* first parameter no */
1407 Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
1408 op->o_req_ndn.bv_val, 0, 0 );
1410 dnParent( &op->o_req_dn, &e.e_name );
1411 dnParent( &op->o_req_ndn, &e.e_nname );
1414 /* check parent for "children" acl */
1415 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
1416 NULL, ACL_WRITE, NULL ) ) {
1417 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1418 "no write access to parent\n",
1420 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1421 send_ldap_result( op, rs );
1426 rs->sr_err = backsql_get_db_conn( op, &dbh );
1427 if ( rs->sr_err != LDAP_SUCCESS ) {
1428 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1429 "could not get connection handle - exiting\n",
1431 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
1432 ? "SQL-backend error" : NULL,
1433 send_ldap_result( op, rs );
1437 rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn );
1438 if ( rs->sr_err != LDAP_SUCCESS ) {
1439 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1440 "could not lookup entry id\n", 0, 0, 0 );
1441 send_ldap_result( op, rs );
1445 rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn );
1446 switch ( rs->sr_err ) {
1447 case LDAP_COMPARE_TRUE:
1448 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1449 "entry \"%s\" has children\n",
1450 op->o_req_dn.bv_val, 0, 0 );
1451 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
1452 rs->sr_text = "subtree delete not supported";
1453 send_ldap_result( op, rs );
1456 case LDAP_COMPARE_FALSE:
1460 send_ldap_result( op, rs );
1464 oc = backsql_id2oc( bi, e_id.oc_id );
1466 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1467 "cannot determine objectclass of entry -- aborting\n",
1469 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1470 rs->sr_text = "operation not permitted within namingContext";
1471 send_ldap_result( op, rs );
1475 if ( oc->bom_delete_proc == NULL ) {
1476 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1477 "delete procedure is not defined "
1478 "for this objectclass - aborting\n", 0, 0, 0 );
1479 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1480 rs->sr_text = "operation not permitted within namingContext";
1481 send_ldap_result( op, rs );
1485 SQLAllocStmt( dbh, &sth );
1486 if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) {
1488 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1489 SQL_INTEGER, 0, 0, &rc, 0, 0 );
1494 SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT,
1495 SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 );
1497 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n",
1498 oc->bom_delete_proc, 0, 0 );
1499 rc = SQLExecDirect( sth, oc->bom_delete_proc, SQL_NTS );
1500 if ( rc != SQL_SUCCESS ) {
1501 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1502 "delete_proc execution failed\n", 0, 0, 0 );
1503 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1504 SQLFreeStmt( sth, SQL_DROP );
1505 rs->sr_err = LDAP_OTHER;
1506 rs->sr_text = "SQL-backend error";
1507 send_ldap_result( op, rs );
1510 #ifndef BACKSQL_REALLOC_STMT
1511 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1512 #else /* BACKSQL_REALLOC_STMT */
1513 SQLFreeStmt( sth, SQL_DROP );
1514 SQLAllocStmt( dbh, &sth );
1515 #endif /* BACKSQL_REALLOC_STMT */
1517 SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
1518 0, 0, &e_id.id, 0, 0 );
1519 rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
1520 if ( rc != SQL_SUCCESS ) {
1521 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1522 "failed to delete record from ldap_entries\n",
1524 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1525 SQLFreeStmt( sth, SQL_DROP );
1526 rs->sr_err = LDAP_OTHER;
1527 rs->sr_text = "SQL-backend error";
1528 send_ldap_result( op, rs );
1532 SQLFreeStmt( sth, SQL_DROP );
1535 * Commit only if all operations succeed
1537 * FIXME: backsql_add() does not fail if add operations
1538 * are not available for some attributes, or if
1539 * a multiple value add actually results in a replace,
1540 * or if a single operation on an attribute fails
1543 SQLTransact( SQL_NULL_HENV, dbh,
1544 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1546 rs->sr_err = LDAP_SUCCESS;
1547 send_ldap_result( op, rs );
1548 Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
1553 #endif /* SLAPD_SQL */