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_values ) ) {
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 #ifdef BACKSQL_ARBITRARY_KEY
183 rc = backsql_BindParamStr( asth, 1,
184 e_id->eid_keyval.bv_val,
185 BACKSQL_MAX_KEY_LEN );
186 #else /* ! BACKSQL_ARBITRARY_KEY */
187 rc = backsql_BindParamID( asth, 1, &e_id->eid_keyval );
188 #endif /* ! BACKSQL_ARBITRARY_KEY */
189 if ( rc != SQL_SUCCESS ) {
190 Debug( LDAP_DEBUG_TRACE,
191 " backsql_modify_internal(): "
192 "error binding key value parameter\n",
194 backsql_PrintErrors( bi->db_env, dbh,
196 SQLFreeStmt( asth, SQL_DROP );
198 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
199 rs->sr_err = LDAP_OTHER;
200 rs->sr_text = "SQL-backend error";
207 rc = SQLExecute( asth );
208 if ( !BACKSQL_SUCCESS( rc ) ) {
209 Debug( LDAP_DEBUG_TRACE,
210 " backsql_modify_internal(): "
211 "error executing attribute query\n",
213 backsql_PrintErrors( bi->db_env, dbh,
215 SQLFreeStmt( asth, SQL_DROP );
217 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
218 rs->sr_err = LDAP_OTHER;
219 rs->sr_text = "SQL-backend error";
226 backsql_BindRowAsStrings( asth, &row );
227 rc = SQLFetch( asth );
228 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
229 for ( i = 0; i < row.ncols; i++ ) {
230 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
232 SQLBindParameter(sth, 1,
240 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
241 #ifdef BACKSQL_ARBITRARY_KEY
242 SQLBindParameter( sth, pno + 1 + po,
244 SQL_C_CHAR, SQL_VARCHAR,
245 0, 0, e_id->eid_keyval.bv_val,
247 #else /* ! BACKSQL_ARBITRARY_KEY */
248 SQLBindParameter( sth, pno + 1 + po,
250 SQL_C_ULONG, SQL_INTEGER,
251 0, 0, &e_id->eid_keyval, 0, 0 );
252 #endif /* ! BACKSQL_ARBITRARY_KEY */
255 * check for syntax needed here
256 * maybe need binary bind?
258 SQLBindParameter(sth, pno + 2 - po,
260 SQL_C_CHAR, SQL_CHAR,
262 strlen( row.cols[ i ] ), 0 );
264 Debug( LDAP_DEBUG_TRACE,
265 " backsql_modify_internal(): "
266 "executing \"%s\"\n",
267 at->bam_delete_proc, 0, 0 );
268 rc = SQLExecDirect( sth,
269 at->bam_delete_proc, SQL_NTS );
270 if ( rc != SQL_SUCCESS ) {
271 Debug( LDAP_DEBUG_TRACE,
272 " backsql_modify_internal(): "
274 "execution failed\n",
276 backsql_PrintErrors( bi->db_env,
279 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
280 rs->sr_err = LDAP_OTHER;
281 rs->sr_text = "SQL-backend error";
285 #ifdef BACKSQL_REALLOC_STMT
286 SQLFreeStmt( sth, SQL_DROP );
287 SQLAllocStmt( dbh, &sth );
288 #endif /* BACKSQL_REALLOC_STMT */
291 backsql_FreeRow( &row );
292 SQLFreeStmt( asth, SQL_DROP );
296 * PASSTHROUGH - to add new attributes -- do NOT add break
299 case SLAP_MOD_SOFTADD:
301 if ( at->bam_add_proc == NULL ) {
302 Debug( LDAP_DEBUG_TRACE,
303 " backsql_modify_internal(): "
304 "add procedure is not defined "
305 "for attribute \"%s\"\n",
306 at->bam_ad->ad_cname.bv_val, 0, 0 );
308 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
309 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
310 rs->sr_text = "operation not permitted "
311 "within namingContext";
318 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
319 "adding new values for attribute \"%s\"\n",
320 at->bam_ad->ad_cname.bv_val, 0, 0 );
321 for ( i = 0, at_val = c_mod->sm_values;
322 at_val->bv_val != NULL;
324 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
326 SQLBindParameter( sth, 1,
328 SQL_C_ULONG, SQL_INTEGER,
333 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
334 #ifdef BACKSQL_ARBITRARY_KEY
335 SQLBindParameter( sth, pno + 1 + po,
337 SQL_C_CHAR, SQL_VARCHAR,
338 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
339 #else /* ! BACKSQL_ARBITRARY_KEY */
340 SQLBindParameter( sth, pno + 1 + po,
342 SQL_C_ULONG, SQL_INTEGER,
343 0, 0, &e_id->eid_keyval, 0, 0 );
344 #endif /* ! BACKSQL_ARBITRARY_KEY */
347 * check for syntax needed here
348 * maybe need binary bind?
350 SQLBindParameter( sth, pno + 2 - po,
352 SQL_C_CHAR, SQL_CHAR,
353 0, 0, at_val->bv_val,
356 Debug( LDAP_DEBUG_TRACE,
357 " backsql_modify_internal(): "
358 "executing \"%s\"\n",
359 at->bam_add_proc, 0, 0 );
360 rc = SQLExecDirect( sth, at->bam_add_proc,
362 if ( rc != SQL_SUCCESS ) {
363 Debug( LDAP_DEBUG_TRACE,
364 " backsql_modify_internal(): "
365 "add_proc execution failed\n",
367 backsql_PrintErrors( bi->db_env,
370 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
371 rs->sr_err = LDAP_OTHER;
372 rs->sr_text = "SQL-backend error";
376 #ifdef BACKSQL_REALLOC_STMT
377 SQLFreeStmt( sth, SQL_DROP );
378 SQLAllocStmt( dbh, &sth );
379 #endif /* BACKSQL_REALLOC_STMT */
383 case LDAP_MOD_DELETE:
384 if ( at->bam_delete_proc == NULL ) {
385 Debug( LDAP_DEBUG_TRACE,
386 " backsql_modify_internal(): "
387 "delete procedure is not defined "
388 "for attribute \"%s\"\n",
389 at->bam_ad->ad_cname.bv_val, 0, 0 );
391 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
392 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
393 rs->sr_text = "operation not permitted "
394 "within namingContext";
401 if ( c_mod->sm_values == NULL ) {
402 Debug( LDAP_DEBUG_TRACE,
403 " backsql_modify_internal(): "
404 "no values given to delete "
405 "for attribute \"%s\" "
406 "-- deleting all values\n",
407 at->bam_ad->ad_cname.bv_val, 0, 0 );
411 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
412 "deleting values for attribute \"%s\"\n",
413 at->bam_ad->ad_cname.bv_val, 0, 0 );
415 for ( i = 0, at_val = c_mod->sm_values;
416 at_val->bv_val != NULL;
418 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
420 SQLBindParameter( sth, 1,
422 SQL_C_ULONG, SQL_INTEGER,
427 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
428 #ifdef BACKSQL_ARBITRARY_KEY
429 SQLBindParameter( sth, pno + 1 + po,
431 SQL_C_CHAR, SQL_VARCHAR,
432 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
433 #else /* ! BACKSQL_ARBITRARY_KEY */
434 SQLBindParameter( sth, pno + 1 + po,
436 SQL_C_ULONG, SQL_INTEGER,
437 0, 0, &e_id->eid_keyval, 0, 0 );
438 #endif /* ! BACKSQL_ARBITRARY_KEY */
441 * check for syntax needed here
442 * maybe need binary bind?
444 SQLBindParameter( sth, pno + 2 - po,
445 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
446 0, 0, at_val->bv_val,
449 Debug( LDAP_DEBUG_TRACE,
450 " backsql_modify_internal(): "
451 "executing \"%s\"\n",
452 at->bam_delete_proc, 0, 0 );
453 rc = SQLExecDirect( sth, at->bam_delete_proc,
455 if ( rc != SQL_SUCCESS ) {
456 Debug( LDAP_DEBUG_TRACE,
457 " backsql_modify_internal(): "
458 "delete_proc execution "
459 "failed\n", 0, 0, 0 );
460 backsql_PrintErrors( bi->db_env,
463 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
464 rs->sr_err = LDAP_OTHER;
465 rs->sr_text = "SQL-backend error";
469 #ifdef BACKSQL_REALLOC_STMT
470 SQLFreeStmt( sth, SQL_DROP );
471 SQLAllocStmt( dbh, &sth );
472 #endif /* BACKSQL_REALLOC_STMT */
476 #ifndef BACKSQL_REALLOC_STMT
477 SQLFreeStmt( sth, SQL_RESET_PARAMS );
478 #else /* BACKSQL_REALLOC_STMT */
479 SQLFreeStmt( sth, SQL_DROP );
480 #endif /* BACKSQL_REALLOC_STMT */
485 #ifndef BACKSQL_REALLOC_STMT
486 SQLFreeStmt( sth, SQL_DROP );
487 #endif /* BACKSQL_REALLOC_STMT */
489 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
490 rs->sr_err, rs->sr_text ? ": " : "",
491 rs->sr_text ? rs->sr_text : "" );
494 * FIXME: should fail in case one change fails?
500 backsql_add( Operation *op, SlapReply *rs )
502 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
505 unsigned long new_keyval = 0;
508 backsql_oc_map_rec *oc = NULL;
509 backsql_at_map_rec *at_rec = NULL;
510 backsql_entryID parent_id = BACKSQL_ENTRYID_INIT;
513 struct berval *at_val;
515 /* first parameter #, parameter order */
516 SQLUSMALLINT pno, po;
517 /* procedure return code */
519 struct berval realdn, realpdn;
521 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry \"%s\"\n",
522 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
525 if ( global_schemacheck ) {
526 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
528 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
530 &rs->sr_text, textbuf, sizeof( textbuf ) );
531 if ( rs->sr_err != LDAP_SUCCESS ) {
532 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
533 "entry failed schema check -- aborting\n",
539 /* search structural objectClass */
540 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
541 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
546 /* there must exist */
547 assert( at != NULL );
549 /* I guess we should play with sub/supertypes to find a suitable oc */
550 oc = backsql_name2oc( bi, &at->a_vals[0] );
553 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
554 "cannot determine objectclass of entry -- aborting\n",
556 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
557 rs->sr_text = "operation not permitted within namingContext";
561 if ( oc->bom_create_proc == NULL ) {
562 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
563 "create procedure is not defined for this objectclass "
564 "- aborting\n", 0, 0, 0 );
565 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
566 rs->sr_text = "operation not permitted within namingContext";
569 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
570 && oc->bom_create_keyval == NULL ) {
571 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
572 "create procedure needs select procedure, "
573 "but none is defined - aborting\n", 0, 0, 0 );
574 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
575 rs->sr_text = "operation not permitted within namingContext";
579 rs->sr_err = backsql_get_db_conn( op, &dbh );
580 if ( rs->sr_err != LDAP_SUCCESS ) {
581 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
582 "could not get connection handle - exiting\n",
584 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
585 ? "SQL-backend error" : NULL;
590 * Check if entry exists
592 realdn = op->oq_add.rs_e->e_name;
593 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
594 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
595 "backsql_api_dn2odbc failed\n",
597 rs->sr_err = LDAP_OTHER;
598 rs->sr_text = "SQL-backend error";
602 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
603 if ( rs->sr_err == LDAP_SUCCESS ) {
604 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
605 "entry \"%s\" exists\n",
606 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
607 rs->sr_err = LDAP_ALREADY_EXISTS;
612 * Check if parent exists
614 dnParent( &op->oq_add.rs_e->e_name, &pdn );
616 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
617 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
618 "backsql_api_dn2odbc failed\n",
620 rs->sr_err = LDAP_OTHER;
621 rs->sr_text = "SQL-backend error";
625 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
626 if ( rs->sr_err != LDAP_SUCCESS ) {
627 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
628 "could not lookup parent entry for new record \"%s\"\n",
631 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
640 char *matched = NULL;
642 if ( realpdn.bv_val != pdn.bv_val ) {
643 ch_free( realpdn.bv_val );
647 dnParent( &dn, &pdn );
650 * Empty DN ("") defaults to LDAP_SUCCESS
653 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
654 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
655 "backsql_api_dn2odbc failed\n",
657 rs->sr_err = LDAP_OTHER;
658 rs->sr_text = "SQL-backend error";
662 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
663 switch ( rs->sr_err ) {
664 case LDAP_NO_SUCH_OBJECT:
665 if ( pdn.bv_len > 0 ) {
668 /* fail over to next case */
671 matched = pdn.bv_val;
672 /* fail over to next case */
675 rs->sr_err = LDAP_NO_SUCH_OBJECT;
676 rs->sr_matched = matched;
683 * create_proc is executed; if expect_return is set, then
684 * an output parameter is bound, which should contain
685 * the id of the added row; otherwise the procedure
686 * is expected to return the id as the first column of a select
691 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
692 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
693 NULL, ACL_WRITE, NULL ) ) {
694 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
698 rc = SQLAllocStmt( dbh, &sth );
699 if ( rc != SQL_SUCCESS ) {
700 rs->sr_err = LDAP_OTHER;
701 rs->sr_text = "SQL-backend error";
705 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
706 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
707 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
710 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\"\n",
711 oc->bom_create_proc, 0, 0 );
712 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
713 if ( rc != SQL_SUCCESS ) {
714 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
715 "create_proc execution failed\n", 0, 0, 0 );
716 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
717 SQLFreeStmt( sth, SQL_DROP );
718 rs->sr_err = LDAP_OTHER;
719 rs->sr_text = "SQL-backend error";
723 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
726 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
728 SQLINTEGER value_len;
730 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
731 #ifndef BACKSQL_REALLOC_STMT
732 SQLFreeStmt( sth, SQL_RESET_PARAMS );
733 #else /* BACKSQL_REALLOC_STMT */
734 SQLFreeStmt( sth, SQL_DROP );
735 rc = SQLAllocStmt( dbh, &sth );
736 if ( rc != SQL_SUCCESS ) {
737 rs->sr_err = LDAP_OTHER;
738 rs->sr_text = "SQL-backend error";
741 #endif /* BACKSQL_REALLOC_STMT */
743 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
744 if ( rc != SQL_SUCCESS ) {
745 rs->sr_err = LDAP_OTHER;
746 rs->sr_text = "SQL-backend error";
752 * the query to know the id of the inserted entry
753 * must be embedded in the create procedure
755 rc = SQLNumResultCols( sth, &ncols );
756 if ( rc != SQL_SUCCESS ) {
757 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
758 "create_proc result evaluation failed\n",
760 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
761 SQLFreeStmt( sth, SQL_DROP );
762 rs->sr_err = LDAP_OTHER;
763 rs->sr_text = "SQL-backend error";
766 } else if ( ncols != 1 ) {
767 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
768 "create_proc result is bogus (ncols=%d)\n",
770 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
771 SQLFreeStmt( sth, SQL_DROP );
772 rs->sr_err = LDAP_OTHER;
773 rs->sr_text = "SQL-backend error";
779 SQLCHAR colname[ 64 ];
780 SQLSMALLINT name_len, col_type, col_scale, col_null;
784 * FIXME: check whether col_type is compatible,
785 * if it can be null and so on ...
787 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
789 (SQLUINTEGER)( sizeof( colname ) - 1 ),
790 &name_len, &col_type,
791 &col_prec, &col_scale, &col_null );
795 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
796 (SQLPOINTER)&new_keyval,
797 (SQLINTEGER)sizeof( new_keyval ),
800 rc = SQLFetch( sth );
802 if ( value_len <= 0 ) {
803 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
804 "create_proc result is empty?\n",
806 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
807 SQLFreeStmt( sth, SQL_DROP );
808 rs->sr_err = LDAP_OTHER;
809 rs->sr_text = "SQL-backend error";
814 #ifndef BACKSQL_REALLOC_STMT
815 SQLFreeStmt( sth, SQL_RESET_PARAMS );
816 #else /* BACKSQL_REALLOC_STMT */
817 SQLFreeStmt( sth, SQL_DROP );
818 #endif /* BACKSQL_REALLOC_STMT */
820 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
821 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
823 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
824 SQLUSMALLINT currpos;
826 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
827 "adding attribute \"%s\"\n",
828 at->a_desc->ad_cname.bv_val, 0, 0 );
832 * - the first occurrence of objectClass, which is used
833 * to determine how to bulid the SQL entry (FIXME ?!?)
834 * - operational attributes
835 * empty attributes (FIXME ?!?)
837 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
841 at_rec = backsql_ad2at( oc, at->a_desc );
843 if ( at_rec == NULL ) {
844 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
845 "attribute \"%s\" is not registered "
846 "in objectclass \"%s\"\n",
847 at->a_desc->ad_cname.bv_val,
848 BACKSQL_OC_NAME( oc ), 0 );
850 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
851 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
852 rs->sr_text = "operation not permitted "
853 "within namingContext";
860 if ( at_rec->bam_add_proc == NULL ) {
861 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
862 "add procedure is not defined "
863 "for attribute \"%s\"\n",
864 at->a_desc->ad_cname.bv_val, 0, 0 );
866 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
867 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
868 rs->sr_text = "operation not permitted "
869 "within namingContext";
876 #ifdef BACKSQL_REALLOC_STMT
877 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
878 if ( rc != SQL_SUCCESS ) {
880 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
881 rs->sr_err = LDAP_OTHER;
882 rs->sr_text = "SQL-backend error";
888 #endif /* BACKSQL_REALLOC_STMT */
890 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
892 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
893 SQL_C_ULONG, SQL_INTEGER,
899 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
900 currpos = pno + 1 + po;
901 SQLBindParameter( sth, currpos,
902 SQL_PARAM_INPUT, SQL_C_ULONG,
903 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
904 currpos = pno + 2 - po;
906 for ( i = 0, at_val = &at->a_vals[ i ];
907 at_val->bv_val != NULL;
908 i++, at_val = &at->a_vals[ i ] ) {
911 * Do not deal with the objectClass that is used
914 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
915 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
921 * check for syntax needed here
922 * maybe need binary bind?
925 backsql_BindParamStr( sth, currpos,
926 at_val->bv_val, at_val->bv_len + 1 );
927 #ifdef SECURITY_PARANOID
928 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
929 "executing \"%s\", id=%ld\n",
930 at_rec->bam_add_proc, new_keyval, 0 );
932 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
933 "executing \"%s\" for val[%d], id=%ld\n",
934 at_rec->bam_add_proc, i, new_keyval );
936 #ifndef BACKSQL_REALLOC_STMT
937 rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
938 #else /* BACKSQL_REALLOC_STMT */
939 rc = SQLExecute( sth );
940 #endif /* BACKSQL_REALLOC_STMT */
941 if ( rc != SQL_SUCCESS ) {
942 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
943 "add_proc execution failed\n",
945 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
947 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
948 rs->sr_err = LDAP_OTHER;
949 rs->sr_text = "SQL-backend error";
954 #ifndef BACKSQL_REALLOC_STMT
955 SQLFreeStmt( sth, SQL_RESET_PARAMS );
956 #else /* BACKSQL_REALLOC_STMT */
957 SQLFreeStmt( sth, SQL_DROP );
958 #endif /* BACKSQL_REALLOC_STMT */
961 #ifdef BACKSQL_REALLOC_STMT
962 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
963 if ( rc != SQL_SUCCESS ) {
964 rs->sr_err = LDAP_OTHER;
965 rs->sr_text = "SQL-backend error";
968 #endif /* BACKSQL_REALLOC_STMT */
970 backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
971 BACKSQL_MAX_DN_LEN );
972 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
973 0, 0, &oc->bom_id, 0, 0 );
974 #ifdef BACKSQL_ARBITRARY_KEY
975 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
976 0, 0, parent_id.eid_id.bv_val, 0, 0 );
977 #else /* ! BACKSQL_ARBITRARY_KEY */
978 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
979 0, 0, &parent_id.eid_id, 0, 0 );
980 #endif /* ! BACKSQL_ARBITRARY_KEY */
981 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
982 0, 0, &new_keyval, 0, 0 );
984 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
985 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
986 #ifdef BACKSQL_ARBITRARY_KEY
987 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
988 "parent_id=%s, keyval=%ld\n",
989 oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
990 #else /* ! BACKSQL_ARBITRARY_KEY */
991 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
992 "parent_id=%ld, keyval=%ld\n",
993 oc->bom_id, parent_id.eid_id, new_keyval );
994 #endif /* ! BACKSQL_ARBITRARY_KEY */
995 #ifndef BACKSQL_REALLOC_STMT
996 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
997 #else /* BACKSQL_REALLOC_STMT */
998 rc = SQLExecute( sth );
999 #endif /* BACKSQL_REALLOC_STMT */
1000 if ( rc != SQL_SUCCESS ) {
1001 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
1002 "could not insert ldap_entries record\n", 0, 0, 0 );
1003 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1006 * execute delete_proc to delete data added !!!
1008 SQLFreeStmt( sth, SQL_DROP );
1009 rs->sr_err = LDAP_OTHER;
1010 rs->sr_text = "SQL-backend error";
1014 SQLFreeStmt( sth, SQL_DROP );
1017 * Commit only if all operations succeed
1019 SQLTransact( SQL_NULL_HENV, dbh,
1020 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1023 * FIXME: NOOP does not work for add -- it works for all
1024 * the other operations, and I don't get the reason :(
1026 * hint: there might be some autocommit in Postgres
1027 * so that when the unique id of the key table is
1028 * automatically increased, there's no rollback.
1029 * We might implement a "rollback" procedure consisting
1030 * in deleting that row.
1034 send_ldap_result( op, rs );
1036 if ( realdn.bv_val != op->oq_add.rs_e->e_name.bv_val ) {
1037 ch_free( realdn.bv_val );
1039 if ( realpdn.bv_val != pdn.bv_val ) {
1040 ch_free( realpdn.bv_val );
1042 if ( parent_id.eid_dn.bv_val != NULL ) {
1043 backsql_free_entryID( &parent_id, 0 );
1046 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(): %d%s%s\n",
1048 rs->sr_text ? ": " : "",
1049 rs->sr_text ? rs->sr_text : "" );
1051 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1054 #endif /* SLAPD_SQL */