2 * Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
4 * Redistribution and use in source and binary forms are permitted only
5 * as authorized by the OpenLDAP Public License. A copy of this
6 * license is available at http://www.OpenLDAP.org/license.html or
7 * in file LICENSE in the top-level directory of the distribution.
15 #include <sys/types.h>
21 #include "schema-map.h"
26 * PostgreSQL 7.0 doesn't work without :(
28 #define BACKSQL_REALLOC_STMT
32 * - the first occurrence of objectClass, which is used
33 * to determine how to bulid the SQL entry (FIXME ?!?)
34 * - operational attributes
35 * empty attributes (FIXME ?!?)
37 #define backsql_attr_skip(ad,vals) \
39 ( (ad) == slap_schema.si_ad_objectClass \
40 && (vals)[ 1 ].bv_val == NULL ) \
41 || is_at_operational( (ad)->ad_type ) \
42 || ( (vals)[ 0 ].bv_val == NULL ) \
46 backsql_modify_internal(
49 backsql_oc_map_rec *oc,
50 backsql_entryID *e_id,
51 Modifications *modlist,
57 int res = LDAP_SUCCESS;
59 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
60 "traversing modifications list\n", 0, 0, 0 );
64 #ifndef BACKSQL_REALLOC_STMT
65 SQLAllocStmt( dbh, &sth );
66 #endif /* BACKSQL_REALLOC_STMT */
68 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
69 AttributeDescription *ad;
70 backsql_at_map_rec *at = NULL;
71 struct berval *at_val;
74 /* first parameter no, parameter order */
76 /* procedure return code */
79 #ifdef BACKSQL_REALLOC_STMT
80 SQLAllocStmt( dbh, &sth );
81 #endif /* BACKSQL_REALLOC_STMT */
86 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
87 "modifying attribute '%s'\n",
88 ad->ad_cname.bv_val, 0, 0 );
90 if ( backsql_attr_skip( ad, c_mod->sm_bvalues ) ) {
94 at = backsql_ad2at( oc, ad );
96 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
97 "attribute provided is not registered "
98 "in objectClass '%s'\n",
99 ad->ad_cname.bv_val, 0, 0 );
101 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
102 res = LDAP_UNWILLING_TO_PERFORM;
103 *text = "operation not permitted "
104 "within namingContext";
111 switch( c_mod->sm_op ) {
112 case LDAP_MOD_REPLACE: {
116 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
117 "replacing values for attribute '%s'\n",
118 at->ad->ad_cname.bv_val, 0, 0 );
120 if ( at->add_proc == NULL ) {
121 Debug( LDAP_DEBUG_TRACE,
122 "backsql_modify_internal(): "
123 "add procedure is not defined "
124 "for attribute '%s' "
125 "- unable to perform replacements\n",
126 at->ad->ad_cname.bv_val, 0, 0 );
128 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
129 res = LDAP_UNWILLING_TO_PERFORM;
130 *text = "operation not permitted "
131 "within namingContext";
138 if ( at->delete_proc == NULL ) {
139 Debug( LDAP_DEBUG_TRACE,
140 "backsql_modify_internal(): "
141 "delete procedure is not defined "
142 "for attribute '%s' "
144 at->ad->ad_cname.bv_val, 0, 0 );
146 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
147 res = LDAP_UNWILLING_TO_PERFORM;
148 *text = "operation not permitted "
149 "within namingContext";
157 rc = backsql_Prepare( dbh, &asth, at->query, 0 );
158 if ( rc != SQL_SUCCESS ) {
159 Debug( LDAP_DEBUG_TRACE,
160 "backsql_modify_internal(): "
161 "error preparing query\n", 0, 0, 0 );
162 backsql_PrintErrors( bi->db_env, dbh,
165 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
167 *text = "SQL-backend error";
174 rc = backsql_BindParamID( asth, 1, &e_id->keyval );
175 if ( rc != SQL_SUCCESS ) {
176 Debug( LDAP_DEBUG_TRACE,
177 "backsql_modify_internal(): "
178 "error binding key value parameter\n",
180 backsql_PrintErrors( bi->db_env, dbh,
182 SQLFreeStmt( asth, SQL_DROP );
184 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
186 *text = "SQL-backend error";
193 rc = SQLExecute( asth );
194 if ( !BACKSQL_SUCCESS( rc ) ) {
195 Debug( LDAP_DEBUG_TRACE,
196 "backsql_modify_internal(): "
197 "error executing attribute query\n",
199 backsql_PrintErrors( bi->db_env, dbh,
201 SQLFreeStmt( asth, SQL_DROP );
203 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
205 *text = "SQL-backend error";
212 backsql_BindRowAsStrings( asth, &row );
213 rc = SQLFetch( asth );
214 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
215 for ( i = 0; i < row.ncols; i++ ) {
216 if ( BACKSQL_IS_DEL( at->expect_return ) ) {
218 SQLBindParameter(sth, 1,
226 po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
227 SQLBindParameter( sth, pno + 1 + po,
229 SQL_C_ULONG, SQL_INTEGER,
230 0, 0, &e_id->keyval, 0, 0 );
233 * check for syntax needed here
234 * maybe need binary bind?
236 SQLBindParameter(sth, pno + 2 - po,
238 SQL_C_CHAR, SQL_CHAR,
240 strlen( row.cols[ i ] ), 0 );
242 Debug( LDAP_DEBUG_TRACE,
243 "backsql_modify_internal(): "
245 at->delete_proc, 0, 0 );
246 rc = SQLExecDirect( sth,
247 at->delete_proc, SQL_NTS );
248 if ( rc != SQL_SUCCESS ) {
249 Debug( LDAP_DEBUG_TRACE,
250 "backsql_modify_internal(): "
252 "execution failed\n",
254 backsql_PrintErrors( bi->db_env,
257 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
259 *text = "SQL-backend error";
263 #ifdef BACKSQL_REALLOC_STMT
264 SQLFreeStmt( sth, SQL_DROP );
265 SQLAllocStmt( dbh, &sth );
266 #endif /* BACKSQL_REALLOC_STMT */
269 backsql_FreeRow( &row );
270 SQLFreeStmt( asth, SQL_DROP );
274 * PASSTHROUGH - to add new attributes -- do NOT add break
277 case SLAP_MOD_SOFTADD:
279 if ( at->add_proc == NULL ) {
280 Debug( LDAP_DEBUG_TRACE,
281 "backsql_modify_internal(): "
282 "add procedure is not defined "
283 "for attribute '%s'\n",
284 at->ad->ad_cname.bv_val, 0, 0 );
286 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
287 res = LDAP_UNWILLING_TO_PERFORM;
288 *text = "operation not permitted "
289 "within namingContext";
296 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
297 "adding new values for attribute '%s'\n",
298 at->ad->ad_cname.bv_val, 0, 0 );
299 for ( i = 0, at_val = c_mod->sm_bvalues;
300 at_val->bv_val != NULL;
302 if ( BACKSQL_IS_ADD( at->expect_return ) ) {
304 SQLBindParameter( sth, 1,
306 SQL_C_ULONG, SQL_INTEGER,
311 po = ( BACKSQL_IS_ADD( at->param_order ) ) > 0;
312 SQLBindParameter( sth, pno + 1 + po,
314 SQL_C_ULONG, SQL_INTEGER,
315 0, 0, &e_id->keyval, 0, 0 );
318 * check for syntax needed here
319 * maybe need binary bind?
321 SQLBindParameter( sth, pno + 2 - po,
323 SQL_C_CHAR, SQL_CHAR,
324 0, 0, at_val->bv_val,
327 Debug( LDAP_DEBUG_TRACE,
328 "backsql_modify_internal(): "
330 at->add_proc, 0, 0 );
331 rc = SQLExecDirect( sth, at->add_proc,
333 if ( rc != SQL_SUCCESS ) {
334 Debug( LDAP_DEBUG_TRACE,
335 "backsql_modify_internal(): "
336 "add_proc execution failed\n",
338 backsql_PrintErrors( bi->db_env,
341 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
343 *text = "SQL-backend error";
347 #ifdef BACKSQL_REALLOC_STMT
348 SQLFreeStmt( sth, SQL_DROP );
349 SQLAllocStmt( dbh, &sth );
350 #endif /* BACKSQL_REALLOC_STMT */
354 case LDAP_MOD_DELETE:
355 if ( at->delete_proc == NULL ) {
356 Debug( LDAP_DEBUG_TRACE,
357 "backsql_modify_internal(): "
358 "delete procedure is not defined "
359 "for attribute '%s'\n",
360 at->ad->ad_cname.bv_val, 0, 0 );
362 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
363 res = LDAP_UNWILLING_TO_PERFORM;
364 *text = "operation not permitted "
365 "within namingContext";
372 if ( c_mod->sm_bvalues == NULL ) {
373 Debug( LDAP_DEBUG_TRACE,
374 "backsql_modify_internal(): "
375 "no values given to delete "
376 "for attribute '%s' "
377 "-- deleting all values\n",
378 at->ad->ad_cname.bv_val, 0, 0 );
382 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
383 "deleting values for attribute '%s'\n",
384 at->ad->ad_cname.bv_val, 0, 0 );
386 for ( i = 0, at_val = c_mod->sm_bvalues;
387 at_val->bv_val != NULL;
389 if ( BACKSQL_IS_DEL( at->expect_return ) ) {
391 SQLBindParameter( sth, 1,
393 SQL_C_ULONG, SQL_INTEGER,
398 po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
399 SQLBindParameter( sth, pno + 1 + po,
401 SQL_C_ULONG, SQL_INTEGER,
402 0, 0, &e_id->keyval, 0, 0 );
405 * check for syntax needed here
406 * maybe need binary bind?
408 SQLBindParameter( sth, pno + 2 - po,
409 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
410 0, 0, at_val->bv_val,
413 Debug( LDAP_DEBUG_TRACE,
414 "backsql_modify_internal(): "
416 at->delete_proc, 0, 0 );
417 rc = SQLExecDirect( sth, at->delete_proc,
419 if ( rc != SQL_SUCCESS ) {
420 Debug( LDAP_DEBUG_TRACE,
421 "backsql_modify_internal(): "
422 "delete_proc execution "
423 "failed\n", 0, 0, 0 );
424 backsql_PrintErrors( bi->db_env,
427 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
429 *text = "SQL-backend error";
433 #ifdef BACKSQL_REALLOC_STMT
434 SQLFreeStmt( sth, SQL_DROP );
435 SQLAllocStmt( dbh, &sth );
436 #endif /* BACKSQL_REALLOC_STMT */
440 #ifndef BACKSQL_REALLOC_STMT
441 SQLFreeStmt( sth, SQL_RESET_PARAMS );
442 #else /* BACKSQL_REALLOC_STMT */
443 SQLFreeStmt( sth, SQL_DROP );
444 #endif /* BACKSQL_REALLOC_STMT */
449 #ifndef BACKSQL_REALLOC_STMT
450 SQLFreeStmt( sth, SQL_DROP );
451 #endif /* BACKSQL_REALLOC_STMT */
454 * FIXME: should fail in case one change fails?
466 Modifications *modlist )
468 backsql_info *bi = (backsql_info*)be->be_private;
470 backsql_oc_map_rec *oc = NULL;
471 backsql_entryID e_id;
474 const char *text = NULL;
477 * FIXME: in case part of the operation cannot be performed
478 * (missing mapping, SQL write fails or so) the entire operation
479 * should be rolled-back
482 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
484 res = backsql_get_db_conn( be, conn, &dbh );
485 if ( res != LDAP_SUCCESS ) {
486 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
487 "could not get connection handle - exiting\n",
490 * FIXME: we don't want to send back
491 * excessively detailed messages
493 send_ldap_result( conn, op, res, "",
494 res == LDAP_OTHER ? "SQL-backend error" : "",
499 res = backsql_dn2id( bi, &e_id, dbh, ndn );
500 if ( res != LDAP_SUCCESS ) {
501 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
502 "could not lookup entry id\n", 0, 0, 0 );
503 send_ldap_result( conn, op, res , "",
504 res == LDAP_OTHER ? "SQL-backend error" : "",
509 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
510 "modifying entry '%s' (id=%ld)\n",
511 e_id.dn.bv_val, e_id.id, 0 );
513 oc = backsql_id2oc( bi, e_id.oc_id );
515 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
516 "cannot determine objectclass of entry -- aborting\n",
519 * FIXME: should never occur, since the entry was built!!!
523 * FIXME: we don't want to send back
524 * excessively detailed messages
526 send_ldap_result( conn, op, LDAP_OTHER, "",
527 "SQL-backend error", NULL, NULL );
534 if ( !acl_check_modlist( be, conn, op, &e, modlist )) {
535 res = LDAP_INSUFFICIENT_ACCESS;
538 res = backsql_modify_internal( bi, dbh, oc, &e_id,
542 if ( res == LDAP_SUCCESS ) {
544 * Commit only if all operations succeed
546 * FIXME: backsql_modify_internal() does not fail
547 * if add/delete operations are not available, or
548 * if a multiple value add actually results in a replace,
549 * or if a single operation on an attribute fails
552 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
554 send_ldap_result( conn, op, res, "", text, NULL, NULL );
555 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
567 struct berval *newrdn,
568 struct berval *nnewrdn,
570 struct berval *newSuperior,
571 struct berval *nnewSuperior )
573 backsql_info *bi = (backsql_info*)be->be_private;
577 backsql_entryID e_id, pe_id, new_pid;
578 backsql_oc_map_rec *oc = NULL;
580 struct berval p_dn, p_ndn,
581 *new_pdn = NULL, *new_npdn = NULL,
583 const char *text = NULL;
584 LDAPRDN *new_rdn = NULL;
585 LDAPRDN *old_rdn = NULL;
589 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
590 "newrdn='%s', newSuperior='%s'\n",
591 dn->bv_val, newrdn->bv_val,
592 newSuperior ? newSuperior->bv_val : "(NULL)" );
593 res = backsql_get_db_conn( be, conn, &dbh );
594 if ( res != LDAP_SUCCESS ) {
595 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
596 "could not get connection handle - exiting\n",
598 send_ldap_result( conn, op, res, "",
599 res == LDAP_OTHER ? "SQL-backend error" : "",
604 res = backsql_dn2id( bi, &e_id, dbh, ndn );
605 if ( res != LDAP_SUCCESS ) {
606 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
607 "could not lookup entry id\n", 0, 0, 0 );
608 send_ldap_result( conn, op, res, "",
609 res == LDAP_OTHER ? "SQL-backend error" : "",
615 * FIXME: check whether entry has children
618 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
621 if ( backsql_has_children( bi, dbh, ndn ) == LDAP_COMPARE_TRUE ) {
622 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
623 "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
624 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
625 NULL, "subtree delete not supported",
630 dnParent( dn, &p_dn );
631 dnParent( ndn, &p_ndn );
634 * namingContext "" is not supported
636 if ( p_dn.bv_len == 0 ) {
637 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
638 "parent is \"\" - aborting\n", 0, 0, 0 );
639 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
640 "", "not allowed within namingContext",
646 * Check for children access to parent
651 if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children,
652 NULL, ACL_WRITE, NULL ) ) {
653 Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
654 res = LDAP_INSUFFICIENT_ACCESS;
660 * namingContext "" is not supported
662 if ( newSuperior->bv_len == 0 ) {
663 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
664 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
665 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM,
666 "", "not allowed within namingContext",
671 new_pdn = newSuperior;
672 new_npdn = nnewSuperior;
675 e.e_nname = *new_npdn;
678 * Check for children access to new parent
680 if ( !access_allowed( be, conn, op, &e,
681 slap_schema.si_ad_children,
682 NULL, ACL_WRITE, NULL ) ) {
683 Debug( LDAP_DEBUG_TRACE, "no access to new parent\n",
685 res = LDAP_INSUFFICIENT_ACCESS;
694 if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
695 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
696 "newSuperior is equal to old parent - ignored\n",
701 if ( newSuperior && dn_match( ndn, new_npdn ) ) {
702 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
703 "newSuperior is equal to entry being moved "
704 "- aborting\n", 0, 0, 0 );
705 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "",
710 build_new_dn( &new_dn, new_pdn, newrdn );
711 if ( dnNormalize2( NULL, &new_dn, &new_ndn ) != LDAP_SUCCESS ) {
712 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
713 "new dn is invalid ('%s') - aborting\n",
714 new_dn.bv_val, 0, 0 );
715 send_ldap_result( conn, op, LDAP_INVALID_DN_SYNTAX, "",
720 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): new entry dn is '%s'\n",
721 new_dn.bv_val, 0, 0 );
723 res = backsql_dn2id( bi, &pe_id, dbh, &p_ndn );
724 if ( res != LDAP_SUCCESS ) {
725 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
726 "could not lookup old parent entry id\n", 0, 0, 0 );
727 send_ldap_result( conn, op, res, "",
728 res == LDAP_OTHER ? "SQL-backend error" : "",
733 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
734 "old parent entry id is %ld\n", pe_id.id, 0, 0 );
736 res = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
737 if ( res != LDAP_SUCCESS ) {
738 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
739 "could not lookup new parent entry id\n", 0, 0, 0 );
740 send_ldap_result( conn, op, res, "",
741 res == LDAP_OTHER ? "SQL-backend error" : "",
746 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
747 "new parent entry id is %ld\n", new_pid.id, 0, 0 );
750 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
751 "executing delentry_query\n", 0, 0, 0 );
752 SQLAllocStmt( dbh, &sth );
753 SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
754 0, 0, &e_id.id, 0, 0 );
755 rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
756 if ( rc != SQL_SUCCESS ) {
757 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
758 "failed to delete record from ldap_entries\n",
760 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
761 send_ldap_result( conn, op, LDAP_OTHER, "",
762 "SQL-backend error", NULL, NULL );
766 SQLFreeStmt( sth, SQL_RESET_PARAMS );
768 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
769 "executing insentry_query\n", 0, 0, 0 );
770 backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
771 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
772 0, 0, &e_id.oc_id, 0, 0 );
773 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
774 0, 0, &new_pid.id, 0, 0 );
775 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
776 0, 0, &e_id.keyval, 0, 0 );
777 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
778 if ( rc != SQL_SUCCESS ) {
779 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
780 "could not insert ldap_entries record\n", 0, 0, 0 );
781 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
782 send_ldap_result( conn, op, LDAP_OTHER, "",
783 "SQL-backend error", NULL, NULL );
788 * Get attribute type and attribute value of our new rdn,
789 * we will need to add that to our new entry
791 if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text,
792 LDAP_DN_FORMAT_LDAP ) ) {
794 LDAP_LOG ( OPERATION, ERR,
795 "backsql_modrdn: can't figure out "
796 "type(s)/values(s) of newrdn\n",
799 Debug( LDAP_DEBUG_TRACE,
800 "backsql_modrdn: can't figure out "
801 "type(s)/values(s) of newrdn\n",
804 rc = LDAP_INVALID_DN_SYNTAX;
809 LDAP_LOG ( OPERATION, RESULTS,
810 "backsql_modrdn: new_rdn_type=\"%s\", "
811 "new_rdn_val=\"%s\"\n",
812 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
813 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
815 Debug( LDAP_DEBUG_TRACE,
816 "backsql_modrdn: new_rdn_type=\"%s\", "
817 "new_rdn_val=\"%s\"\n",
818 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
819 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
822 if ( deleteoldrdn ) {
823 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
824 LDAP_DN_FORMAT_LDAP ) ) {
826 LDAP_LOG ( OPERATION, ERR,
827 "backsql_modrdn: can't figure out "
828 "type(s)/values(s) of old_rdn\n",
831 Debug( LDAP_DEBUG_TRACE,
832 "backsql_modrdn: can't figure out "
833 "the old_rdn type(s)/value(s)\n",
843 res = slap_modrdn2mods( be, conn, op, &e, old_rdn, new_rdn,
844 deleteoldrdn, &mod );
845 if ( res != LDAP_SUCCESS ) {
849 if ( !acl_check_modlist( be, conn, op, &e, mod )) {
850 res = LDAP_INSUFFICIENT_ACCESS;
854 oc = backsql_id2oc( bi, e_id.oc_id );
855 res = backsql_modify_internal( bi, dbh, oc, &e_id, mod, &text );
857 if ( res == LDAP_SUCCESS ) {
860 * Commit only if all operations succeed
862 * FIXME: backsql_modify_internal() does not fail
863 * if add/delete operations are not available, or
864 * if a multiple value add actually results in a replace,
865 * or if a single operation on an attribute fails for any
868 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
872 SQLFreeStmt( sth, SQL_DROP );
874 if ( new_dn.bv_val ) {
875 ch_free( new_dn.bv_val );
878 if ( new_ndn.bv_val ) {
879 ch_free( new_ndn.bv_val );
882 /* LDAP v2 supporting correct attribute handling. */
883 if ( new_rdn != NULL ) {
884 ldap_rdnfree( new_rdn );
886 if ( old_rdn != NULL ) {
887 ldap_rdnfree( old_rdn );
891 for (; mod; mod=tmp ) {
897 send_ldap_result( conn, op, res, "", text, NULL, NULL );
899 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
910 backsql_info *bi = (backsql_info*)be->be_private;
913 unsigned long new_keyval = 0;
916 backsql_oc_map_rec *oc = NULL;
917 backsql_at_map_rec *at_rec = NULL;
918 backsql_entryID e_id, parent_id;
922 struct berval *at_val;
924 /* first parameter #, parameter order */
925 SQLUSMALLINT pno, po;
926 /* procedure return code */
929 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n",
930 e->e_name.bv_val, 0, 0 );
932 for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
933 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
934 if ( global_schemacheck ) {
935 const char *text = NULL;
936 char textbuf[ 1024 ];
937 size_t textlen = sizeof( textbuf );
940 int rc = structural_class( at->a_vals, &soc,
941 NULL, &text, textbuf, textlen );
942 if ( rc != LDAP_SUCCESS ) {
945 oc = backsql_name2oc( bi, &soc );
950 * FIXME: only the objectClass provided first
951 * is considered when creating a new entry
953 oc = backsql_name2oc( bi, &at->a_vals[ 0 ] );
960 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
961 "cannot determine objectclass of entry -- aborting\n",
963 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
964 "operation not permitted within namingContext",
969 if ( oc->create_proc == NULL ) {
970 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
971 "create procedure is not defined for this objectclass "
972 "- aborting\n", 0, 0, 0 );
973 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
974 "operation not permitted within namingContext",
978 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
979 && oc->create_keyval == NULL ) {
980 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
981 "create procedure needs select, but none is defined"
982 "- aborting\n", 0, 0, 0 );
983 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
984 "operation not permitted within namingContext",
989 prc = backsql_get_db_conn( be, conn, &dbh );
990 if ( prc != LDAP_SUCCESS ) {
991 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
992 "could not get connection handle - exiting\n",
994 send_ldap_result( conn, op, prc, "",
995 prc == LDAP_OTHER ? "SQL-backend error" : "",
1001 * Check if entry exists
1003 res = backsql_dn2id( bi, &e_id, dbh, &e->e_name );
1004 if ( res == LDAP_SUCCESS ) {
1005 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1006 "entry '%s' exists\n",
1007 e->e_name.bv_val, 0, 0 );
1008 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "",
1014 * Check if parent exists
1016 dnParent( &e->e_name, &pdn );
1017 res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
1018 if ( res != LDAP_SUCCESS ) {
1021 * NO SUCH OBJECT seems more appropriate
1023 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1024 "could not lookup parent entry for new record '%s'\n",
1027 if ( res != LDAP_NO_SUCH_OBJECT ) {
1028 send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
1040 dnParent( &dn, &pdn );
1043 * Empty DN ("") defaults to LDAP_SUCCESS
1045 res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
1047 case LDAP_NO_SUCH_OBJECT:
1048 if ( pdn.bv_len > 0 ) {
1051 /* fail over to next case */
1054 matched = pdn.bv_val;
1055 /* fail over to next case */
1058 send_ldap_result( conn, op, res, matched,
1066 * create_proc is executed; if expect_return is set, then
1067 * an output parameter is bound, which should contain
1068 * the id of the added row; otherwise the procedure
1069 * is expected to return the id as the first column of a select
1074 dnParent( &e->e_nname, &p.e_nname );
1075 if ( !access_allowed( be, conn, op, &p, slap_schema.si_ad_children,
1076 NULL, ACL_WRITE, NULL ) ) {
1077 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
1078 NULL, NULL, NULL, NULL );
1082 #ifndef BACKSQL_REALLOC_STMT
1083 rc = SQLAllocStmt( dbh, &sth );
1084 #else /* BACKSQL_REALLOC_STMT */
1085 rc = backsql_Prepare( dbh, &sth, oc->create_proc, 0 );
1086 #endif /* BACKSQL_REALLOC_STMT */
1087 if ( rc != SQL_SUCCESS ) {
1088 send_ldap_result( conn, op, LDAP_OTHER, "",
1089 "SQL-backend error", NULL, NULL );
1093 if ( BACKSQL_IS_ADD( oc->expect_return ) ) {
1094 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1095 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1098 Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s'\n",
1099 oc->create_proc, 0, 0 );
1100 #ifndef BACKSQL_REALLOC_STMT
1101 rc = SQLExecDirect( sth, oc->create_proc, SQL_NTS );
1102 #else /* BACKSQL_REALLOC_STMT */
1103 rc = SQLExecute( sth );
1104 #endif /* BACKSQL_REALLOC_STMT */
1105 if ( rc != SQL_SUCCESS ) {
1106 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1107 "create_proc execution failed\n", 0, 0, 0 );
1108 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1109 SQLFreeStmt( sth, SQL_DROP );
1110 send_ldap_result( conn, op, LDAP_OTHER, "",
1111 "SQL-backend error", NULL, NULL );
1115 if ( !BACKSQL_IS_ADD( oc->expect_return ) ) {
1119 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1120 #ifndef BACKSQL_REALLOC_STMT
1121 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1122 #else /* BACKSQL_REALLOC_STMT */
1123 SQLFreeStmt( sth, SQL_DROP );
1124 rc = SQLAllocStmt( dbh, &sth );
1125 if ( rc != SQL_SUCCESS ) {
1126 send_ldap_result( conn, op, LDAP_OTHER, "",
1127 "SQL-backend error", NULL, NULL );
1130 #endif /* BACKSQL_REALLOC_STMT */
1132 rc = SQLExecDirect( sth, oc->create_keyval, SQL_NTS );
1133 if ( rc != SQL_SUCCESS ) {
1134 send_ldap_result( conn, op, LDAP_OTHER, "",
1135 "SQL-backend error", NULL, NULL );
1141 * the query to know the id of the inserted entry
1142 * must be embedded in the create procedure
1144 rc = SQLNumResultCols( sth, &ncols );
1145 if ( rc != SQL_SUCCESS ) {
1146 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1147 "create_proc result evaluation failed\n",
1149 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1150 SQLFreeStmt( sth, SQL_DROP );
1151 send_ldap_result( conn, op, LDAP_OTHER, "",
1152 "SQL-backend error", NULL, NULL );
1155 } else if ( ncols != 1 ) {
1156 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1157 "create_proc result is bogus (ncols=%d)\n",
1159 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1160 SQLFreeStmt( sth, SQL_DROP );
1161 send_ldap_result( conn, op, LDAP_OTHER, "",
1162 "SQL-backend error", NULL, NULL );
1168 SQLCHAR colname[ 64 ];
1169 SQLSMALLINT name_len, col_type, col_scale, col_null;
1173 * FIXME: check whether col_type is compatible,
1174 * if it can be null and so on ...
1176 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
1178 (SQLUINTEGER)( sizeof( colname ) - 1 ),
1179 &name_len, &col_type,
1180 &col_prec, &col_scale, &col_null );
1184 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1185 (SQLPOINTER)&new_keyval,
1186 (SQLINTEGER)sizeof( new_keyval ),
1189 rc = SQLFetch( sth );
1193 * FIXME: what does is_null mean?
1196 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1197 "create_proc result is null\n",
1199 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1200 SQLFreeStmt( sth, SQL_DROP );
1201 send_ldap_result( conn, op, LDAP_OTHER, "",
1202 "SQL-backend error", NULL, NULL );
1208 #ifndef BACKSQL_REALLOC_STMT
1209 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1210 #else /* BACKSQL_REALLOC_STMT */
1211 SQLFreeStmt( sth, SQL_DROP );
1212 #endif /* BACKSQL_REALLOC_STMT */
1214 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1215 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
1217 for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
1218 SQLUSMALLINT currpos;
1220 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1221 "adding attribute '%s'\n",
1222 at->a_desc->ad_cname.bv_val, 0, 0 );
1226 * - the first occurrence of objectClass, which is used
1227 * to determine how to bulid the SQL entry (FIXME ?!?)
1228 * - operational attributes
1229 * empty attributes (FIXME ?!?)
1231 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1235 at_rec = backsql_ad2at( oc, at->a_desc );
1237 if ( at_rec == NULL ) {
1238 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1239 "attribute '%s' is not registered "
1240 "in objectclass '%s'\n",
1241 at->a_desc->ad_cname.bv_val,
1242 oc->name.bv_val, 0 );
1244 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1245 send_ldap_result( conn, op,
1246 LDAP_UNWILLING_TO_PERFORM, "",
1247 "operation not permitted "
1248 "within namingContext",
1256 if ( at_rec->add_proc == NULL ) {
1257 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1258 "add procedure is not defined "
1259 "for attribute '%s'\n",
1260 at->a_desc->ad_cname.bv_val, 0, 0 );
1262 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1263 send_ldap_result( conn, op,
1264 LDAP_UNWILLING_TO_PERFORM, "",
1265 "operation not permitted "
1266 "within namingContext",
1274 #ifdef BACKSQL_REALLOC_STMT
1275 rc = backsql_Prepare( dbh, &sth, at_rec->add_proc, 0 );
1276 if ( rc != SQL_SUCCESS ) {
1278 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1279 send_ldap_result( conn, op,
1281 "SQL-backend error",
1288 #endif /* BACKSQL_REALLOC_STMT */
1290 if ( BACKSQL_IS_ADD( at_rec->expect_return ) ) {
1292 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
1293 SQL_C_ULONG, SQL_INTEGER,
1299 po = ( BACKSQL_IS_ADD( at_rec->param_order ) ) > 0;
1300 currpos = pno + 1 + po;
1301 SQLBindParameter( sth, currpos,
1302 SQL_PARAM_INPUT, SQL_C_ULONG,
1303 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1304 currpos = pno + 2 - po;
1306 for ( i = 0, at_val = &at->a_vals[ i ];
1307 at_val->bv_val != NULL;
1308 i++, at_val = &at->a_vals[ i ] ) {
1311 * Do not deal with the objectClass that is used
1312 * to build the entry
1314 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1315 if ( ber_bvcmp( at_val, &oc->name ) == 0 ) {
1321 * check for syntax needed here
1322 * maybe need binary bind?
1325 backsql_BindParamStr( sth, currpos,
1326 at_val->bv_val, at_val->bv_len + 1 );
1327 #ifdef SECURITY_PARANOID
1328 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1329 "executing '%s', id=%ld\n",
1330 at_rec->add_proc, new_keyval, 0 );
1332 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1333 "executing '%s' with val='%s', id=%ld\n",
1334 at_rec->add_proc, at_val->bv_val, new_keyval );
1336 #ifndef BACKSQL_REALLOC_STMT
1337 rc = SQLExecDirect( sth, at_rec->add_proc, SQL_NTS );
1338 #else /* BACKSQL_REALLOC_STMT */
1339 rc = SQLExecute( sth );
1340 #endif /* BACKSQL_REALLOC_STMT */
1341 if ( rc != SQL_SUCCESS ) {
1342 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1343 "add_proc execution failed\n",
1345 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1347 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1348 send_ldap_result( conn, op,
1350 "SQL-backend error",
1356 #ifndef BACKSQL_REALLOC_STMT
1357 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1358 #else /* BACKSQL_REALLOC_STMT */
1359 SQLFreeStmt( sth, SQL_DROP );
1360 #endif /* BACKSQL_REALLOC_STMT */
1363 #ifdef BACKSQL_REALLOC_STMT
1364 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1365 if ( rc != SQL_SUCCESS ) {
1366 send_ldap_result( conn, op, LDAP_OTHER, "",
1367 "SQL-backend error", NULL, NULL );
1370 #endif /* BACKSQL_REALLOC_STMT */
1372 backsql_BindParamStr( sth, 1, e->e_name.bv_val, BACKSQL_MAX_DN_LEN );
1373 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1374 0, 0, &oc->id, 0, 0 );
1375 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1376 0, 0, &parent_id.id, 0, 0 );
1377 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1378 0, 0, &new_keyval, 0, 0 );
1380 Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s' for dn '%s'\n",
1381 bi->insentry_query, e->e_name.bv_val, 0 );
1382 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, "
1383 "keyval=%ld\n", oc->id, parent_id.id, new_keyval );
1384 #ifndef BACKSQL_REALLOC_STMT
1385 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1386 #else /* BACKSQL_REALLOC_STMT */
1387 rc = SQLExecute( sth );
1388 #endif /* BACKSQL_REALLOC_STMT */
1389 if ( rc != SQL_SUCCESS ) {
1390 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1391 "could not insert ldap_entries record\n", 0, 0, 0 );
1392 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1395 * execute delete_proc to delete data added !!!
1397 SQLFreeStmt( sth, SQL_DROP );
1398 send_ldap_result( conn, op, LDAP_OTHER, "",
1399 "SQL-backend error", NULL, NULL );
1403 SQLFreeStmt( sth, SQL_DROP );
1406 * Commit only if all operations succeed
1408 * FIXME: backsql_add() does not fail if add operations
1409 * are not available for some attributes, or if
1410 * a multiple value add actually results in a replace,
1411 * or if a single operation on an attribute fails
1414 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1416 send_ldap_result( conn, op, LDAP_SUCCESS, "",
1427 struct berval *ndn )
1429 backsql_info *bi = (backsql_info*)be->be_private;
1433 backsql_oc_map_rec *oc = NULL;
1434 backsql_entryID e_id;
1437 /* first parameter no */
1440 Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
1441 ndn->bv_val, 0, 0 );
1443 dnParent( dn, &e.e_name );
1444 dnParent( ndn, &e.e_nname );
1447 /* check parent for "children" acl */
1448 if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children,
1449 NULL, ACL_WRITE, NULL ) ) {
1450 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1451 "no write access to parent\n",
1453 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
1454 "", NULL, NULL, NULL );
1459 res = backsql_get_db_conn( be, conn, &dbh );
1460 if ( res != LDAP_SUCCESS ) {
1461 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1462 "could not get connection handle - exiting\n",
1464 send_ldap_result( conn, op, res, "",
1465 res == LDAP_OTHER ? "SQL-backend error" : "",
1470 res = backsql_dn2id( bi, &e_id, dbh, ndn );
1471 if ( res != LDAP_SUCCESS ) {
1472 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1473 "could not lookup entry id\n", 0, 0, 0 );
1474 send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
1478 res = backsql_has_children( bi, dbh, ndn );
1480 case LDAP_COMPARE_TRUE:
1481 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1482 "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
1483 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
1484 NULL, "subtree delete not supported",
1488 case LDAP_COMPARE_FALSE:
1492 send_ldap_result( conn, op, res, NULL, NULL, NULL, NULL );
1496 oc = backsql_id2oc( bi, e_id.oc_id );
1498 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1499 "cannot determine objectclass of entry "
1500 "-- aborting\n", 0, 0, 0 );
1501 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
1502 "operation not permitted within namingContext",
1507 if ( oc->delete_proc == NULL ) {
1508 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1509 "delete procedure is not defined "
1510 "for this objectclass - aborting\n", 0, 0, 0 );
1511 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
1512 "operation not permitted within namingContext",
1517 SQLAllocStmt( dbh, &sth );
1518 if ( BACKSQL_IS_DEL( oc->expect_return ) ) {
1520 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1521 SQL_INTEGER, 0, 0, &rc, 0, 0 );
1526 SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT,
1527 SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 );
1529 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n",
1530 oc->delete_proc, 0, 0 );
1531 rc = SQLExecDirect( sth, oc->delete_proc, SQL_NTS );
1532 if ( rc != SQL_SUCCESS ) {
1533 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1534 "delete_proc execution failed\n", 0, 0, 0 );
1535 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1536 SQLFreeStmt( sth, SQL_DROP );
1537 send_ldap_result( conn, op, LDAP_OTHER, "",
1538 "SQL-backend error", NULL, NULL );
1541 #ifndef BACKSQL_REALLOC_STMT
1542 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1543 #else /* BACKSQL_REALLOC_STMT */
1544 SQLFreeStmt( sth, SQL_DROP );
1545 SQLAllocStmt( dbh, &sth );
1546 #endif /* BACKSQL_REALLOC_STMT */
1548 SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
1549 0, 0, &e_id.id, 0, 0 );
1550 rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
1551 if ( rc != SQL_SUCCESS ) {
1552 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1553 "failed to delete record from ldap_entries\n",
1555 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1556 SQLFreeStmt( sth, SQL_DROP );
1557 send_ldap_result( conn, op, LDAP_OTHER, "",
1558 "SQL-backend error", NULL, NULL );
1562 SQLFreeStmt( sth, SQL_DROP );
1565 * Commit only if all operations succeed
1567 * FIXME: backsql_add() does not fail if add operations
1568 * are not available for some attributes, or if
1569 * a multiple value add actually results in a replace,
1570 * or if a single operation on an attribute fails
1573 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1575 send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
1576 Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
1580 #endif /* SLAPD_SQL */