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(\"%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(\"%s\"): "
533 "entry failed schema check -- aborting\n",
534 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
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(\"%s\"): "
554 "cannot map structuralObjectClass \"%s\" -- aborting\n",
555 op->oq_add.rs_e->e_name.bv_val,
556 at->a_vals[0].bv_val, 0 );
557 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
558 rs->sr_text = "operation not permitted within namingContext";
562 if ( oc->bom_create_proc == NULL ) {
563 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
564 "create procedure is not defined "
565 "for structuralObjectClass \"%s\" - aborting\n",
566 op->oq_add.rs_e->e_name.bv_val,
567 at->a_vals[0].bv_val, 0 );
568 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
569 rs->sr_text = "operation not permitted within namingContext";
572 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
573 && oc->bom_create_keyval == NULL ) {
574 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
575 "create procedure needs select procedure, "
576 "but none is defined for structuralObjectClass \"%s\" "
578 op->oq_add.rs_e->e_name.bv_val,
579 at->a_vals[0].bv_val, 0 );
580 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
581 rs->sr_text = "operation not permitted within namingContext";
585 rs->sr_err = backsql_get_db_conn( op, &dbh );
586 if ( rs->sr_err != LDAP_SUCCESS ) {
587 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
588 "could not get connection handle - exiting\n",
589 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
590 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
591 ? "SQL-backend error" : NULL;
596 * Check if entry exists
598 realdn = op->oq_add.rs_e->e_name;
599 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
600 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
601 "backsql_api_dn2odbc(\"%s\") failed\n",
602 op->oq_add.rs_e->e_name.bv_val,
603 op->oq_add.rs_e->e_name.bv_val, 0 );
604 rs->sr_err = LDAP_OTHER;
605 rs->sr_text = "SQL-backend error";
609 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
610 if ( rs->sr_err == LDAP_SUCCESS ) {
611 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
613 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
614 rs->sr_err = LDAP_ALREADY_EXISTS;
619 * Check if parent exists
621 dnParent( &op->oq_add.rs_e->e_name, &pdn );
623 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
624 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
625 "backsql_api_dn2odbc(\"%s\") failed\n",
626 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
627 rs->sr_err = LDAP_OTHER;
628 rs->sr_text = "SQL-backend error";
632 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
633 if ( rs->sr_err != LDAP_SUCCESS ) {
634 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
635 "could not lookup parent entry for new record \"%s\"\n",
636 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
638 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
647 char *matched = NULL;
649 if ( realpdn.bv_val != pdn.bv_val ) {
650 ch_free( realpdn.bv_val );
654 dnParent( &dn, &pdn );
657 * Empty DN ("") defaults to LDAP_SUCCESS
660 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
661 Debug( LDAP_DEBUG_TRACE,
662 " backsql_add(\"%s\"): "
663 "backsql_api_dn2odbc failed\n",
664 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
665 rs->sr_err = LDAP_OTHER;
666 rs->sr_text = "SQL-backend error";
670 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
671 switch ( rs->sr_err ) {
672 case LDAP_NO_SUCH_OBJECT:
673 if ( pdn.bv_len > 0 ) {
676 /* fail over to next case */
679 matched = pdn.bv_val;
680 /* fail over to next case */
683 rs->sr_err = LDAP_NO_SUCH_OBJECT;
684 rs->sr_matched = matched;
691 * create_proc is executed; if expect_return is set, then
692 * an output parameter is bound, which should contain
693 * the id of the added row; otherwise the procedure
694 * is expected to return the id as the first column of a select
699 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
700 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
701 NULL, ACL_WRITE, NULL ) ) {
702 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
706 rc = SQLAllocStmt( dbh, &sth );
707 if ( rc != SQL_SUCCESS ) {
708 rs->sr_err = LDAP_OTHER;
709 rs->sr_text = "SQL-backend error";
713 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
714 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
715 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
718 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n",
719 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
720 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
721 if ( rc != SQL_SUCCESS ) {
722 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
723 "create_proc execution failed\n",
724 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
725 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
726 SQLFreeStmt( sth, SQL_DROP );
727 rs->sr_err = LDAP_OTHER;
728 rs->sr_text = "SQL-backend error";
732 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
735 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
737 SQLINTEGER value_len;
739 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
740 #ifndef BACKSQL_REALLOC_STMT
741 SQLFreeStmt( sth, SQL_RESET_PARAMS );
742 #else /* BACKSQL_REALLOC_STMT */
743 SQLFreeStmt( sth, SQL_DROP );
744 rc = SQLAllocStmt( dbh, &sth );
745 if ( rc != SQL_SUCCESS ) {
746 rs->sr_err = LDAP_OTHER;
747 rs->sr_text = "SQL-backend error";
750 #endif /* BACKSQL_REALLOC_STMT */
752 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
753 if ( rc != SQL_SUCCESS ) {
754 rs->sr_err = LDAP_OTHER;
755 rs->sr_text = "SQL-backend error";
761 * the query to know the id of the inserted entry
762 * must be embedded in the create procedure
764 rc = SQLNumResultCols( sth, &ncols );
765 if ( rc != SQL_SUCCESS ) {
766 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
767 "create_proc result evaluation failed\n",
768 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
769 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
770 SQLFreeStmt( sth, SQL_DROP );
771 rs->sr_err = LDAP_OTHER;
772 rs->sr_text = "SQL-backend error";
775 } else if ( ncols != 1 ) {
776 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
777 "create_proc result is bogus (ncols=%d)\n",
778 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
779 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
780 SQLFreeStmt( sth, SQL_DROP );
781 rs->sr_err = LDAP_OTHER;
782 rs->sr_text = "SQL-backend error";
788 SQLCHAR colname[ 64 ];
789 SQLSMALLINT name_len, col_type, col_scale, col_null;
793 * FIXME: check whether col_type is compatible,
794 * if it can be null and so on ...
796 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
798 (SQLUINTEGER)( sizeof( colname ) - 1 ),
799 &name_len, &col_type,
800 &col_prec, &col_scale, &col_null );
804 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
805 (SQLPOINTER)&new_keyval,
806 (SQLINTEGER)sizeof( new_keyval ),
809 rc = SQLFetch( sth );
811 if ( value_len <= 0 ) {
812 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
813 "create_proc result is empty?\n",
814 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
815 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
816 SQLFreeStmt( sth, SQL_DROP );
817 rs->sr_err = LDAP_OTHER;
818 rs->sr_text = "SQL-backend error";
823 #ifndef BACKSQL_REALLOC_STMT
824 SQLFreeStmt( sth, SQL_RESET_PARAMS );
825 #else /* BACKSQL_REALLOC_STMT */
826 SQLFreeStmt( sth, SQL_DROP );
827 #endif /* BACKSQL_REALLOC_STMT */
829 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
830 "create_proc returned keyval=%ld\n",
831 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
833 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
834 SQLUSMALLINT currpos;
836 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
837 "adding attribute \"%s\"\n",
838 at->a_desc->ad_cname.bv_val, 0, 0 );
842 * - the first occurrence of objectClass, which is used
843 * to determine how to bulid the SQL entry (FIXME ?!?)
844 * - operational attributes
845 * empty attributes (FIXME ?!?)
847 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
851 at_rec = backsql_ad2at( oc, at->a_desc );
853 if ( at_rec == NULL ) {
854 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
855 "attribute \"%s\" is not registered "
856 "in objectclass \"%s\"\n",
857 op->oq_add.rs_e->e_name.bv_val,
858 at->a_desc->ad_cname.bv_val,
859 BACKSQL_OC_NAME( oc ) );
861 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
862 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
863 rs->sr_text = "operation not permitted "
864 "within namingContext";
871 if ( at_rec->bam_add_proc == NULL ) {
872 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
873 "add procedure is not defined "
874 "for attribute \"%s\" "
875 "of structuralObjectClass \"%s\"\n",
876 op->oq_add.rs_e->e_name.bv_val,
877 at->a_desc->ad_cname.bv_val,
878 BACKSQL_OC_NAME( oc ) );
880 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
881 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
882 rs->sr_text = "operation not permitted "
883 "within namingContext";
890 #ifdef BACKSQL_REALLOC_STMT
891 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
892 if ( rc != SQL_SUCCESS ) {
894 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
895 rs->sr_err = LDAP_OTHER;
896 rs->sr_text = "SQL-backend error";
902 #endif /* BACKSQL_REALLOC_STMT */
904 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
906 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
907 SQL_C_ULONG, SQL_INTEGER,
913 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
914 currpos = pno + 1 + po;
915 SQLBindParameter( sth, currpos,
916 SQL_PARAM_INPUT, SQL_C_ULONG,
917 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
918 currpos = pno + 2 - po;
920 for ( i = 0, at_val = &at->a_vals[ i ];
921 at_val->bv_val != NULL;
922 i++, at_val = &at->a_vals[ i ] ) {
923 char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
926 * Do not deal with the objectClass that is used
929 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
930 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
936 * check for syntax needed here
937 * maybe need binary bind?
940 backsql_BindParamStr( sth, currpos,
941 at_val->bv_val, at_val->bv_len + 1 );
944 snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
946 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
947 "executing \"%s\" %s\n",
948 op->oq_add.rs_e->e_name.bv_val,
949 at_rec->bam_add_proc, logbuf );
951 #ifndef BACKSQL_REALLOC_STMT
952 rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
953 #else /* BACKSQL_REALLOC_STMT */
954 rc = SQLExecute( sth );
955 #endif /* BACKSQL_REALLOC_STMT */
956 if ( rc != SQL_SUCCESS ) {
957 Debug( LDAP_DEBUG_TRACE,
958 " backsql_add(\"%s\"): "
959 "add_proc execution failed\n",
960 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
961 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
963 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
964 rs->sr_err = LDAP_OTHER;
965 rs->sr_text = "SQL-backend error";
970 #ifndef BACKSQL_REALLOC_STMT
971 SQLFreeStmt( sth, SQL_RESET_PARAMS );
972 #else /* BACKSQL_REALLOC_STMT */
973 SQLFreeStmt( sth, SQL_DROP );
974 #endif /* BACKSQL_REALLOC_STMT */
977 #ifdef BACKSQL_REALLOC_STMT
978 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
979 if ( rc != SQL_SUCCESS ) {
980 rs->sr_err = LDAP_OTHER;
981 rs->sr_text = "SQL-backend error";
984 #endif /* BACKSQL_REALLOC_STMT */
986 backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
987 BACKSQL_MAX_DN_LEN );
988 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
989 0, 0, &oc->bom_id, 0, 0 );
990 #ifdef BACKSQL_ARBITRARY_KEY
991 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
992 0, 0, parent_id.eid_id.bv_val, 0, 0 );
993 #else /* ! BACKSQL_ARBITRARY_KEY */
994 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
995 0, 0, &parent_id.eid_id, 0, 0 );
996 #endif /* ! BACKSQL_ARBITRARY_KEY */
997 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
998 0, 0, &new_keyval, 0, 0 );
1000 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
1001 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1002 #ifdef BACKSQL_ARBITRARY_KEY
1003 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1004 "parent_id=%s, keyval=%ld\n",
1005 oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1006 #else /* ! BACKSQL_ARBITRARY_KEY */
1007 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1008 "parent_id=%ld, keyval=%ld\n",
1009 oc->bom_id, parent_id.eid_id, new_keyval );
1010 #endif /* ! BACKSQL_ARBITRARY_KEY */
1011 #ifndef BACKSQL_REALLOC_STMT
1012 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1013 #else /* BACKSQL_REALLOC_STMT */
1014 rc = SQLExecute( sth );
1015 #endif /* BACKSQL_REALLOC_STMT */
1016 if ( rc != SQL_SUCCESS ) {
1017 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1018 "could not insert ldap_entries record\n",
1019 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1020 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1023 * execute delete_proc to delete data added !!!
1025 SQLFreeStmt( sth, SQL_DROP );
1026 rs->sr_err = LDAP_OTHER;
1027 rs->sr_text = "SQL-backend error";
1031 SQLFreeStmt( sth, SQL_DROP );
1034 * Commit only if all operations succeed
1036 SQLTransact( SQL_NULL_HENV, dbh,
1037 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1040 * FIXME: NOOP does not work for add -- it works for all
1041 * the other operations, and I don't get the reason :(
1043 * hint: there might be some autocommit in Postgres
1044 * so that when the unique id of the key table is
1045 * automatically increased, there's no rollback.
1046 * We might implement a "rollback" procedure consisting
1047 * in deleting that row.
1051 send_ldap_result( op, rs );
1053 if ( realdn.bv_val != op->oq_add.rs_e->e_name.bv_val ) {
1054 ch_free( realdn.bv_val );
1056 if ( realpdn.bv_val != pdn.bv_val ) {
1057 ch_free( realpdn.bv_val );
1059 if ( parent_id.eid_dn.bv_val != NULL ) {
1060 backsql_free_entryID( &parent_id, 0 );
1063 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1064 op->oq_add.rs_e->e_name.bv_val,
1066 rs->sr_text ? rs->sr_text : "" );
1068 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1071 #endif /* SLAPD_SQL */