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"
31 #include "proto-sql.h"
35 * - the first occurrence of objectClass, which is used
36 * to determine how to build the SQL entry (FIXME ?!?)
37 * - operational attributes
38 * empty attributes (FIXME ?!?)
40 #define backsql_attr_skip(ad,vals) \
42 ( (ad) == slap_schema.si_ad_objectClass \
43 && (vals)[ 1 ].bv_val == NULL ) \
44 || is_at_operational( (ad)->ad_type ) \
45 || ( (vals)[ 0 ].bv_val == NULL ) \
49 backsql_modify_internal(
53 backsql_oc_map_rec *oc,
54 backsql_entryID *e_id,
55 Modifications *modlist )
57 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
62 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
63 "traversing modifications list\n", 0, 0, 0 );
65 #ifndef BACKSQL_REALLOC_STMT
66 SQLAllocStmt( dbh, &sth );
67 #endif /* BACKSQL_REALLOC_STMT */
69 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
70 AttributeDescription *ad;
71 backsql_at_map_rec *at = NULL;
72 struct berval *at_val;
75 /* first parameter no, parameter order */
77 /* procedure return code */
80 #ifdef BACKSQL_REALLOC_STMT
81 SQLAllocStmt( dbh, &sth );
82 #endif /* BACKSQL_REALLOC_STMT */
87 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
88 "modifying attribute \"%s\" according to "
89 "mappings for objectClass \"%s\"\n",
90 ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
92 if ( backsql_attr_skip( ad, c_mod->sm_bvalues ) ) {
96 at = backsql_ad2at( oc, ad );
98 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
99 "attribute \"%s\" is not registered "
100 "in objectClass \"%s\"\n",
101 ad->ad_cname.bv_val, oc, 0 );
103 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
104 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
105 rs->sr_text = "operation not permitted "
106 "within namingContext";
113 switch( c_mod->sm_op ) {
114 case LDAP_MOD_REPLACE: {
118 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
119 "replacing values for attribute \"%s\"\n",
120 at->bam_ad->ad_cname.bv_val, 0, 0 );
122 if ( at->bam_add_proc == NULL ) {
123 Debug( LDAP_DEBUG_TRACE,
124 " backsql_modify_internal(): "
125 "add procedure is not defined "
126 "for attribute \"%s\" "
127 "- unable to perform replacements\n",
128 at->bam_ad->ad_cname.bv_val, 0, 0 );
130 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
131 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
132 rs->sr_text = "operation not permitted "
133 "within namingContext";
140 if ( at->bam_delete_proc == NULL ) {
141 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
142 Debug( LDAP_DEBUG_TRACE,
143 " backsql_modify_internal(): "
144 "delete procedure is not defined "
145 "for attribute \"%s\"\n",
146 at->bam_ad->ad_cname.bv_val, 0, 0 );
148 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
149 rs->sr_text = "operation not permitted "
150 "within namingContext";
154 Debug( LDAP_DEBUG_TRACE,
155 " backsql_modify_internal(): "
156 "delete procedure is not defined "
157 "for attribute \"%s\" "
159 at->bam_ad->ad_cname.bv_val, 0, 0 );
165 rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
166 if ( rc != SQL_SUCCESS ) {
167 Debug( LDAP_DEBUG_TRACE,
168 " backsql_modify_internal(): "
169 "error preparing query\n", 0, 0, 0 );
170 backsql_PrintErrors( bi->db_env, dbh,
173 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
174 rs->sr_err = LDAP_OTHER;
175 rs->sr_text = "SQL-backend error";
182 rc = backsql_BindParamID( asth, 1, &e_id->keyval );
183 if ( rc != SQL_SUCCESS ) {
184 Debug( LDAP_DEBUG_TRACE,
185 " backsql_modify_internal(): "
186 "error binding key value parameter\n",
188 backsql_PrintErrors( bi->db_env, dbh,
190 SQLFreeStmt( asth, SQL_DROP );
192 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
193 rs->sr_err = LDAP_OTHER;
194 rs->sr_text = "SQL-backend error";
201 rc = SQLExecute( asth );
202 if ( !BACKSQL_SUCCESS( rc ) ) {
203 Debug( LDAP_DEBUG_TRACE,
204 " backsql_modify_internal(): "
205 "error executing attribute query\n",
207 backsql_PrintErrors( bi->db_env, dbh,
209 SQLFreeStmt( asth, SQL_DROP );
211 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
212 rs->sr_err = LDAP_OTHER;
213 rs->sr_text = "SQL-backend error";
220 backsql_BindRowAsStrings( asth, &row );
221 rc = SQLFetch( asth );
222 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
223 for ( i = 0; i < row.ncols; i++ ) {
224 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
226 SQLBindParameter(sth, 1,
234 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
235 SQLBindParameter( sth, pno + 1 + po,
237 SQL_C_ULONG, SQL_INTEGER,
238 0, 0, &e_id->keyval, 0, 0 );
241 * check for syntax needed here
242 * maybe need binary bind?
244 SQLBindParameter(sth, pno + 2 - po,
246 SQL_C_CHAR, SQL_CHAR,
248 strlen( row.cols[ i ] ), 0 );
250 Debug( LDAP_DEBUG_TRACE,
251 " backsql_modify_internal(): "
252 "executing \"%s\"\n",
253 at->bam_delete_proc, 0, 0 );
254 rc = SQLExecDirect( sth,
255 at->bam_delete_proc, SQL_NTS );
256 if ( rc != SQL_SUCCESS ) {
257 Debug( LDAP_DEBUG_TRACE,
258 " backsql_modify_internal(): "
260 "execution failed\n",
262 backsql_PrintErrors( bi->db_env,
265 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
266 rs->sr_err = LDAP_OTHER;
267 rs->sr_text = "SQL-backend error";
271 #ifdef BACKSQL_REALLOC_STMT
272 SQLFreeStmt( sth, SQL_DROP );
273 SQLAllocStmt( dbh, &sth );
274 #endif /* BACKSQL_REALLOC_STMT */
277 backsql_FreeRow( &row );
278 SQLFreeStmt( asth, SQL_DROP );
282 * PASSTHROUGH - to add new attributes -- do NOT add break
285 case SLAP_MOD_SOFTADD:
287 if ( at->bam_add_proc == NULL ) {
288 Debug( LDAP_DEBUG_TRACE,
289 " backsql_modify_internal(): "
290 "add procedure is not defined "
291 "for attribute \"%s\"\n",
292 at->bam_ad->ad_cname.bv_val, 0, 0 );
294 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
295 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
296 rs->sr_text = "operation not permitted "
297 "within namingContext";
304 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
305 "adding new values for attribute \"%s\"\n",
306 at->bam_ad->ad_cname.bv_val, 0, 0 );
307 for ( i = 0, at_val = c_mod->sm_bvalues;
308 at_val->bv_val != NULL;
310 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
312 SQLBindParameter( sth, 1,
314 SQL_C_ULONG, SQL_INTEGER,
319 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
320 SQLBindParameter( sth, pno + 1 + po,
322 SQL_C_ULONG, SQL_INTEGER,
323 0, 0, &e_id->keyval, 0, 0 );
326 * check for syntax needed here
327 * maybe need binary bind?
329 SQLBindParameter( sth, pno + 2 - po,
331 SQL_C_CHAR, SQL_CHAR,
332 0, 0, at_val->bv_val,
335 Debug( LDAP_DEBUG_TRACE,
336 " backsql_modify_internal(): "
337 "executing \"%s\"\n",
338 at->bam_add_proc, 0, 0 );
339 rc = SQLExecDirect( sth, at->bam_add_proc,
341 if ( rc != SQL_SUCCESS ) {
342 Debug( LDAP_DEBUG_TRACE,
343 " backsql_modify_internal(): "
344 "add_proc execution failed\n",
346 backsql_PrintErrors( bi->db_env,
349 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
350 rs->sr_err = LDAP_OTHER;
351 rs->sr_text = "SQL-backend error";
355 #ifdef BACKSQL_REALLOC_STMT
356 SQLFreeStmt( sth, SQL_DROP );
357 SQLAllocStmt( dbh, &sth );
358 #endif /* BACKSQL_REALLOC_STMT */
362 case LDAP_MOD_DELETE:
363 if ( at->bam_delete_proc == NULL ) {
364 Debug( LDAP_DEBUG_TRACE,
365 " backsql_modify_internal(): "
366 "delete procedure is not defined "
367 "for attribute \"%s\"\n",
368 at->bam_ad->ad_cname.bv_val, 0, 0 );
370 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
371 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
372 rs->sr_text = "operation not permitted "
373 "within namingContext";
380 if ( c_mod->sm_bvalues == NULL ) {
381 Debug( LDAP_DEBUG_TRACE,
382 " backsql_modify_internal(): "
383 "no values given to delete "
384 "for attribute \"%s\" "
385 "-- deleting all values\n",
386 at->bam_ad->ad_cname.bv_val, 0, 0 );
390 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
391 "deleting values for attribute \"%s\"\n",
392 at->bam_ad->ad_cname.bv_val, 0, 0 );
394 for ( i = 0, at_val = c_mod->sm_bvalues;
395 at_val->bv_val != NULL;
397 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
399 SQLBindParameter( sth, 1,
401 SQL_C_ULONG, SQL_INTEGER,
406 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
407 SQLBindParameter( sth, pno + 1 + po,
409 SQL_C_ULONG, SQL_INTEGER,
410 0, 0, &e_id->keyval, 0, 0 );
413 * check for syntax needed here
414 * maybe need binary bind?
416 SQLBindParameter( sth, pno + 2 - po,
417 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
418 0, 0, at_val->bv_val,
421 Debug( LDAP_DEBUG_TRACE,
422 " backsql_modify_internal(): "
423 "executing \"%s\"\n",
424 at->bam_delete_proc, 0, 0 );
425 rc = SQLExecDirect( sth, at->bam_delete_proc,
427 if ( rc != SQL_SUCCESS ) {
428 Debug( LDAP_DEBUG_TRACE,
429 " backsql_modify_internal(): "
430 "delete_proc execution "
431 "failed\n", 0, 0, 0 );
432 backsql_PrintErrors( bi->db_env,
435 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
436 rs->sr_err = LDAP_OTHER;
437 rs->sr_text = "SQL-backend error";
441 #ifdef BACKSQL_REALLOC_STMT
442 SQLFreeStmt( sth, SQL_DROP );
443 SQLAllocStmt( dbh, &sth );
444 #endif /* BACKSQL_REALLOC_STMT */
448 #ifndef BACKSQL_REALLOC_STMT
449 SQLFreeStmt( sth, SQL_RESET_PARAMS );
450 #else /* BACKSQL_REALLOC_STMT */
451 SQLFreeStmt( sth, SQL_DROP );
452 #endif /* BACKSQL_REALLOC_STMT */
457 #ifndef BACKSQL_REALLOC_STMT
458 SQLFreeStmt( sth, SQL_DROP );
459 #endif /* BACKSQL_REALLOC_STMT */
461 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
462 rs->sr_err, rs->sr_text ? ": " : "",
463 rs->sr_text ? rs->sr_text : "" );
466 * FIXME: should fail in case one change fails?
472 backsql_add( Operation *op, SlapReply *rs )
474 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
477 unsigned long new_keyval = 0;
480 backsql_oc_map_rec *oc = NULL;
481 backsql_at_map_rec *at_rec = NULL;
482 backsql_entryID e_id, parent_id;
485 struct berval *at_val;
487 /* first parameter #, parameter order */
488 SQLUSMALLINT pno, po;
489 /* procedure return code */
492 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry \"%s\"\n",
493 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
496 if ( global_schemacheck ) {
497 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
499 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
501 &rs->sr_text, textbuf, sizeof( textbuf ) );
502 if ( rs->sr_err != LDAP_SUCCESS ) {
503 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
504 "entry failed schema check -- aborting\n",
510 /* search structural objectClass */
511 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
512 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
517 /* there must exist */
518 assert( at != NULL );
520 /* I guess we should play with sub/supertypes to find a suitable oc */
521 oc = backsql_name2oc( bi, &at->a_vals[0] );
524 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
525 "cannot determine objectclass of entry -- aborting\n",
527 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
528 rs->sr_text = "operation not permitted within namingContext";
532 if ( oc->bom_create_proc == NULL ) {
533 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
534 "create procedure is not defined for this objectclass "
535 "- aborting\n", 0, 0, 0 );
536 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
537 rs->sr_text = "operation not permitted within namingContext";
540 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
541 && oc->bom_create_keyval == NULL ) {
542 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
543 "create procedure needs select procedure, "
544 "but none is defined - aborting\n", 0, 0, 0 );
545 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
546 rs->sr_text = "operation not permitted within namingContext";
550 rs->sr_err = backsql_get_db_conn( op, &dbh );
551 if ( rs->sr_err != LDAP_SUCCESS ) {
552 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
553 "could not get connection handle - exiting\n",
555 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
556 ? "SQL-backend error" : NULL;
561 * Check if entry exists
563 rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->oq_add.rs_e->e_name );
564 if ( rs->sr_err == LDAP_SUCCESS ) {
565 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
566 "entry \"%s\" exists\n",
567 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
568 rs->sr_err = LDAP_ALREADY_EXISTS;
573 * Check if parent exists
575 dnParent( &op->oq_add.rs_e->e_name, &pdn );
576 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
577 if ( rs->sr_err != LDAP_SUCCESS ) {
578 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
579 "could not lookup parent entry for new record \"%s\"\n",
582 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
591 char *matched = NULL;
594 dnParent( &dn, &pdn );
597 * Empty DN ("") defaults to LDAP_SUCCESS
599 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
600 switch ( rs->sr_err ) {
601 case LDAP_NO_SUCH_OBJECT:
602 if ( pdn.bv_len > 0 ) {
605 /* fail over to next case */
608 matched = pdn.bv_val;
609 /* fail over to next case */
612 rs->sr_err = LDAP_NO_SUCH_OBJECT;
613 rs->sr_matched = matched;
620 * create_proc is executed; if expect_return is set, then
621 * an output parameter is bound, which should contain
622 * the id of the added row; otherwise the procedure
623 * is expected to return the id as the first column of a select
628 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
629 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
630 NULL, ACL_WRITE, NULL ) ) {
631 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
635 rc = SQLAllocStmt( dbh, &sth );
636 if ( rc != SQL_SUCCESS ) {
637 rs->sr_err = LDAP_OTHER;
638 rs->sr_text = "SQL-backend error";
642 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
643 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
644 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
647 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\"\n",
648 oc->bom_create_proc, 0, 0 );
649 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
650 if ( rc != SQL_SUCCESS ) {
651 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
652 "create_proc execution failed\n", 0, 0, 0 );
653 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
654 SQLFreeStmt( sth, SQL_DROP );
655 rs->sr_err = LDAP_OTHER;
656 rs->sr_text = "SQL-backend error";
660 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
663 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
665 SQLINTEGER value_len;
667 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
668 #ifndef BACKSQL_REALLOC_STMT
669 SQLFreeStmt( sth, SQL_RESET_PARAMS );
670 #else /* BACKSQL_REALLOC_STMT */
671 SQLFreeStmt( sth, SQL_DROP );
672 rc = SQLAllocStmt( dbh, &sth );
673 if ( rc != SQL_SUCCESS ) {
674 rs->sr_err = LDAP_OTHER;
675 rs->sr_text = "SQL-backend error";
678 #endif /* BACKSQL_REALLOC_STMT */
680 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
681 if ( rc != SQL_SUCCESS ) {
682 rs->sr_err = LDAP_OTHER;
683 rs->sr_text = "SQL-backend error";
689 * the query to know the id of the inserted entry
690 * must be embedded in the create procedure
692 rc = SQLNumResultCols( sth, &ncols );
693 if ( rc != SQL_SUCCESS ) {
694 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
695 "create_proc result evaluation failed\n",
697 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
698 SQLFreeStmt( sth, SQL_DROP );
699 rs->sr_err = LDAP_OTHER;
700 rs->sr_text = "SQL-backend error";
703 } else if ( ncols != 1 ) {
704 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
705 "create_proc result is bogus (ncols=%d)\n",
707 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
708 SQLFreeStmt( sth, SQL_DROP );
709 rs->sr_err = LDAP_OTHER;
710 rs->sr_text = "SQL-backend error";
716 SQLCHAR colname[ 64 ];
717 SQLSMALLINT name_len, col_type, col_scale, col_null;
721 * FIXME: check whether col_type is compatible,
722 * if it can be null and so on ...
724 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
726 (SQLUINTEGER)( sizeof( colname ) - 1 ),
727 &name_len, &col_type,
728 &col_prec, &col_scale, &col_null );
732 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
733 (SQLPOINTER)&new_keyval,
734 (SQLINTEGER)sizeof( new_keyval ),
737 rc = SQLFetch( sth );
739 if ( value_len <= 0 ) {
740 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
741 "create_proc result is empty?\n",
743 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
744 SQLFreeStmt( sth, SQL_DROP );
745 rs->sr_err = LDAP_OTHER;
746 rs->sr_text = "SQL-backend error";
751 #ifndef BACKSQL_REALLOC_STMT
752 SQLFreeStmt( sth, SQL_RESET_PARAMS );
753 #else /* BACKSQL_REALLOC_STMT */
754 SQLFreeStmt( sth, SQL_DROP );
755 #endif /* BACKSQL_REALLOC_STMT */
757 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
758 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
760 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
761 SQLUSMALLINT currpos;
763 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
764 "adding attribute \"%s\"\n",
765 at->a_desc->ad_cname.bv_val, 0, 0 );
769 * - the first occurrence of objectClass, which is used
770 * to determine how to bulid the SQL entry (FIXME ?!?)
771 * - operational attributes
772 * empty attributes (FIXME ?!?)
774 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
778 at_rec = backsql_ad2at( oc, at->a_desc );
780 if ( at_rec == NULL ) {
781 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
782 "attribute \"%s\" is not registered "
783 "in objectclass \"%s\"\n",
784 at->a_desc->ad_cname.bv_val,
785 BACKSQL_OC_NAME( oc ), 0 );
787 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
788 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
789 rs->sr_text = "operation not permitted "
790 "within namingContext";
797 if ( at_rec->bam_add_proc == NULL ) {
798 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
799 "add procedure is not defined "
800 "for attribute \"%s\"\n",
801 at->a_desc->ad_cname.bv_val, 0, 0 );
803 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
804 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
805 rs->sr_text = "operation not permitted "
806 "within namingContext";
813 #ifdef BACKSQL_REALLOC_STMT
814 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
815 if ( rc != SQL_SUCCESS ) {
817 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
818 rs->sr_err = LDAP_OTHER;
819 rs->sr_text = "SQL-backend error";
825 #endif /* BACKSQL_REALLOC_STMT */
827 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
829 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
830 SQL_C_ULONG, SQL_INTEGER,
836 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
837 currpos = pno + 1 + po;
838 SQLBindParameter( sth, currpos,
839 SQL_PARAM_INPUT, SQL_C_ULONG,
840 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
841 currpos = pno + 2 - po;
843 for ( i = 0, at_val = &at->a_vals[ i ];
844 at_val->bv_val != NULL;
845 i++, at_val = &at->a_vals[ i ] ) {
848 * Do not deal with the objectClass that is used
851 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
852 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
858 * check for syntax needed here
859 * maybe need binary bind?
862 backsql_BindParamStr( sth, currpos,
863 at_val->bv_val, at_val->bv_len + 1 );
864 #ifdef SECURITY_PARANOID
865 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
866 "executing \"%s\", id=%ld\n",
867 at_rec->bam_add_proc, new_keyval, 0 );
869 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
870 "executing \"%s\" for val[%d], id=%ld\n",
871 at_rec->bam_add_proc, i, new_keyval );
873 #ifndef BACKSQL_REALLOC_STMT
874 rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
875 #else /* BACKSQL_REALLOC_STMT */
876 rc = SQLExecute( sth );
877 #endif /* BACKSQL_REALLOC_STMT */
878 if ( rc != SQL_SUCCESS ) {
879 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
880 "add_proc execution failed\n",
882 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
884 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
885 rs->sr_err = LDAP_OTHER;
886 rs->sr_text = "SQL-backend error";
891 #ifndef BACKSQL_REALLOC_STMT
892 SQLFreeStmt( sth, SQL_RESET_PARAMS );
893 #else /* BACKSQL_REALLOC_STMT */
894 SQLFreeStmt( sth, SQL_DROP );
895 #endif /* BACKSQL_REALLOC_STMT */
898 #ifdef BACKSQL_REALLOC_STMT
899 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
900 if ( rc != SQL_SUCCESS ) {
901 rs->sr_err = LDAP_OTHER;
902 rs->sr_text = "SQL-backend error";
905 #endif /* BACKSQL_REALLOC_STMT */
907 backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
908 BACKSQL_MAX_DN_LEN );
909 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
910 0, 0, &oc->bom_id, 0, 0 );
911 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
912 0, 0, &parent_id.id, 0, 0 );
913 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
914 0, 0, &new_keyval, 0, 0 );
916 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
917 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
918 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, "
919 "keyval=%ld\n", oc->bom_id, parent_id.id, new_keyval );
920 #ifndef BACKSQL_REALLOC_STMT
921 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
922 #else /* BACKSQL_REALLOC_STMT */
923 rc = SQLExecute( sth );
924 #endif /* BACKSQL_REALLOC_STMT */
925 if ( rc != SQL_SUCCESS ) {
926 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
927 "could not insert ldap_entries record\n", 0, 0, 0 );
928 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
931 * execute delete_proc to delete data added !!!
933 SQLFreeStmt( sth, SQL_DROP );
934 rs->sr_err = LDAP_OTHER;
935 rs->sr_text = "SQL-backend error";
939 SQLFreeStmt( sth, SQL_DROP );
942 * Commit only if all operations succeed
944 SQLTransact( SQL_NULL_HENV, dbh,
945 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
948 * FIXME: NOOP does not work for add -- it works for all
949 * the other operations, and I don't get the reason :(
951 * hint: there might be some autocommit in Postgres
952 * so that when the unique id of the key table is
953 * automatically increased, there's no rollback.
954 * We might implement a "rollback" procedure consisting
955 * in deleting that row.
959 send_ldap_result( op, rs );
961 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(): %d%s%s\n",
963 rs->sr_text ? ": " : "",
964 rs->sr_text ? rs->sr_text : "" );
966 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
969 #endif /* SLAPD_SQL */