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.
24 #include <sys/types.h>
25 #include "ac/string.h"
28 #include "proto-sql.h"
30 #ifdef BACKSQL_SYNCPROV
32 #endif /* BACKSQL_SYNCPROV */
36 * - null values (e.g. delete modification)
37 * - single occurrence of objectClass, because it is already used
38 * to determine how to build the SQL entry
39 * - operational attributes
42 #define backsql_attr_skip(ad, vals) \
44 ( (ad) == slap_schema.si_ad_objectClass \
45 && (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
46 || is_at_operational( (ad)->ad_type ) \
47 || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
51 backsql_modify_delete_all_values(
55 backsql_entryID *e_id,
56 backsql_at_map_rec *at )
58 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
64 if ( at->bam_delete_proc == NULL ) {
65 Debug( LDAP_DEBUG_TRACE,
66 " backsql_modify_delete_all_values(): "
67 "missing attribute value delete procedure "
69 at->bam_ad->ad_cname.bv_val, 0, 0 );
70 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
71 rs->sr_text = "SQL-backend error";
72 return rs->sr_err = LDAP_OTHER;
78 rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
79 if ( rc != SQL_SUCCESS ) {
80 Debug( LDAP_DEBUG_TRACE,
81 " backsql_modify_delete_all_values(): "
82 "error preparing attribute value select query "
84 at->bam_query, 0, 0 );
85 backsql_PrintErrors( bi->sql_db_env, dbh,
88 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
89 rs->sr_text = "SQL-backend error";
90 return rs->sr_err = LDAP_OTHER;
95 rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval );
96 if ( rc != SQL_SUCCESS ) {
97 Debug( LDAP_DEBUG_TRACE,
98 " backsql_modify_delete_all_values(): "
99 "error binding key value parameter "
100 "to attribute value select query\n",
102 backsql_PrintErrors( bi->sql_db_env, dbh,
104 SQLFreeStmt( asth, SQL_DROP );
106 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
107 rs->sr_text = "SQL-backend error";
108 return rs->sr_err = LDAP_OTHER;
114 rc = SQLExecute( asth );
115 if ( !BACKSQL_SUCCESS( rc ) ) {
116 Debug( LDAP_DEBUG_TRACE,
117 " backsql_modify_delete_all_values(): "
118 "error executing attribute value select query\n",
120 backsql_PrintErrors( bi->sql_db_env, dbh,
122 SQLFreeStmt( asth, SQL_DROP );
124 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
125 rs->sr_text = "SQL-backend error";
126 return rs->sr_err = LDAP_OTHER;
132 backsql_BindRowAsStrings( asth, &row );
133 for ( rc = SQLFetch( asth );
134 BACKSQL_SUCCESS( rc );
135 rc = SQLFetch( asth ) )
138 /* first parameter no, parameter order */
139 SQLUSMALLINT pno, po;
140 /* procedure return code */
143 for ( i = 0; i < row.ncols; i++ ) {
147 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
148 if ( rc != SQL_SUCCESS ) {
149 Debug( LDAP_DEBUG_TRACE,
150 " backsql_modify_delete_all_values(): "
151 "error preparing attribute value "
154 at->bam_delete_proc, 0, 0 );
155 backsql_PrintErrors( bi->sql_db_env, dbh,
158 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
159 rs->sr_text = "SQL-backend error";
160 return rs->sr_err = LDAP_OTHER;
166 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
168 rc = backsql_BindParamInt( sth, 1,
169 SQL_PARAM_OUTPUT, &prc );
170 if ( rc != SQL_SUCCESS ) {
171 Debug( LDAP_DEBUG_TRACE,
172 " backsql_modify_delete_all_values(): "
173 "error binding output parameter for %s[%d]\n",
174 at->bam_ad->ad_cname.bv_val, i, 0 );
175 backsql_PrintErrors( bi->sql_db_env, dbh,
177 SQLFreeStmt( sth, SQL_DROP );
179 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
180 rs->sr_text = "SQL-backend error";
181 return rs->sr_err = LDAP_OTHER;
190 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
191 rc = backsql_BindParamID( sth, pno + 1 + po,
192 SQL_PARAM_INPUT, &e_id->eid_keyval );
193 if ( rc != SQL_SUCCESS ) {
194 Debug( LDAP_DEBUG_TRACE,
195 " backsql_modify_delete_all_values(): "
196 "error binding keyval parameter for %s[%d]\n",
197 at->bam_ad->ad_cname.bv_val, i, 0 );
198 backsql_PrintErrors( bi->sql_db_env, dbh,
200 SQLFreeStmt( sth, SQL_DROP );
202 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
203 rs->sr_text = "SQL-backend error";
204 return rs->sr_err = LDAP_OTHER;
209 #ifdef BACKSQL_ARBITRARY_KEY
210 Debug( LDAP_DEBUG_TRACE,
211 " backsql_modify_delete_all_values() "
213 pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
214 #else /* ! BACKSQL_ARBITRARY_KEY */
215 Debug( LDAP_DEBUG_TRACE,
216 " backsql_modify_delete_all_values() "
218 pno + 1 + po, e_id->eid_keyval, 0 );
219 #endif /* ! BACKSQL_ARBITRARY_KEY */
222 * check for syntax needed here
223 * maybe need binary bind?
225 col_len = strlen( row.cols[ i ] );
226 rc = backsql_BindParamStr( sth, pno + 2 - po,
227 SQL_PARAM_INPUT, row.cols[ i ], col_len );
228 if ( rc != SQL_SUCCESS ) {
229 Debug( LDAP_DEBUG_TRACE,
230 " backsql_modify_delete_all_values(): "
231 "error binding value parameter for %s[%d]\n",
232 at->bam_ad->ad_cname.bv_val, i, 0 );
233 backsql_PrintErrors( bi->sql_db_env, dbh,
235 SQLFreeStmt( sth, SQL_DROP );
237 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
238 rs->sr_text = "SQL-backend error";
239 return rs->sr_err = LDAP_OTHER;
245 Debug( LDAP_DEBUG_TRACE,
246 " backsql_modify_delete_all_values(): "
247 "arg%d=%s; executing \"%s\"\n",
248 pno + 2 - po, row.cols[ i ],
249 at->bam_delete_proc );
250 rc = SQLExecute( sth );
251 if ( rc != SQL_SUCCESS ) {
252 Debug( LDAP_DEBUG_TRACE,
253 " backsql_modify_delete_all_values(): "
255 "execution failed\n",
257 backsql_PrintErrors( bi->sql_db_env,
260 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
261 SQLFreeStmt( sth, SQL_DROP );
262 rs->sr_text = "SQL-backend error";
263 return rs->sr_err = LDAP_OTHER;
266 SQLFreeStmt( sth, SQL_DROP );
269 backsql_FreeRow( &row );
270 SQLFreeStmt( asth, SQL_DROP );
276 backsql_modify_internal(
280 backsql_oc_map_rec *oc,
281 backsql_entryID *e_id,
282 Modifications *modlist )
284 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
289 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
290 "traversing modifications list\n", 0, 0, 0 );
292 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
293 AttributeDescription *ad;
295 static char *sm_ops[] = { "add", "delete", "replace", "increment", NULL };
299 /* NOTE: some day we'll have to pass
300 * the normalized values as well */
303 backsql_at_map_rec *at = NULL;
304 struct berval *at_val;
306 /* first parameter position, parameter order */
307 SQLUSMALLINT pno, po;
308 /* procedure return code */
311 ad = ml->sml_mod.sm_desc;
312 sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
313 sm_values = ml->sml_mod.sm_values;
315 sm_nvalues = ml->sml_mod.sm_nvalues;
318 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
319 "modifying attribute \"%s\" (%s) according to "
320 "mappings for objectClass \"%s\"\n",
321 ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) );
323 if ( backsql_attr_skip( ad, sm_values ) ) {
327 at = backsql_ad2at( oc, ad );
329 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
330 "attribute \"%s\" is not registered "
331 "in objectClass \"%s\"\n",
332 ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
334 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
335 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
336 rs->sr_text = "operation not permitted "
337 "within namingContext";
345 case LDAP_MOD_REPLACE: {
346 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
347 "replacing values for attribute \"%s\"\n",
348 at->bam_ad->ad_cname.bv_val, 0, 0 );
350 if ( at->bam_add_proc == NULL ) {
351 Debug( LDAP_DEBUG_TRACE,
352 " backsql_modify_internal(): "
353 "add procedure is not defined "
354 "for attribute \"%s\" "
355 "- unable to perform replacements\n",
356 at->bam_ad->ad_cname.bv_val, 0, 0 );
358 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
359 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
360 rs->sr_text = "operation not permitted "
361 "within namingContext";
368 if ( at->bam_delete_proc == NULL ) {
369 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
370 Debug( LDAP_DEBUG_TRACE,
371 " backsql_modify_internal(): "
372 "delete procedure is not defined "
373 "for attribute \"%s\"\n",
374 at->bam_ad->ad_cname.bv_val, 0, 0 );
376 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
377 rs->sr_text = "operation not permitted "
378 "within namingContext";
382 Debug( LDAP_DEBUG_TRACE,
383 " backsql_modify_internal(): "
384 "delete procedure is not defined "
385 "for attribute \"%s\" "
387 at->bam_ad->ad_cname.bv_val, 0, 0 );
393 rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
394 if ( rs->sr_err != LDAP_SUCCESS ) {
398 /* LDAP_MOD_DELETE gets here if all values must be deleted */
399 if ( sm_op == LDAP_MOD_DELETE ) {
405 * PASSTHROUGH - to add new attributes -- do NOT add break
408 /* case SLAP_MOD_SOFTADD: */
410 if ( at->bam_add_proc == NULL ) {
411 Debug( LDAP_DEBUG_TRACE,
412 " backsql_modify_internal(): "
413 "add procedure is not defined "
414 "for attribute \"%s\"\n",
415 at->bam_ad->ad_cname.bv_val, 0, 0 );
417 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
418 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
419 rs->sr_text = "operation not permitted "
420 "within namingContext";
427 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
428 "adding new values for attribute \"%s\"\n",
429 at->bam_ad->ad_cname.bv_val, 0, 0 );
431 /* can't add a NULL val array */
432 assert( sm_values != NULL );
434 for ( i = 0, at_val = sm_values;
435 !BER_BVISNULL( at_val );
438 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
439 if ( rc != SQL_SUCCESS ) {
440 Debug( LDAP_DEBUG_TRACE,
441 " backsql_modify_internal(): "
442 "error preparing add query\n",
444 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
446 rs->sr_err = LDAP_OTHER;
447 rs->sr_text = "SQL-backend error";
451 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
453 rc = backsql_BindParamInt( sth, 1,
454 SQL_PARAM_OUTPUT, &prc );
455 if ( rc != SQL_SUCCESS ) {
456 Debug( LDAP_DEBUG_TRACE,
457 " backsql_modify_internal(): "
458 "error binding output parameter for %s[%d]\n",
459 at->bam_ad->ad_cname.bv_val, i, 0 );
460 backsql_PrintErrors( bi->sql_db_env, dbh,
462 SQLFreeStmt( sth, SQL_DROP );
464 rs->sr_text = "SQL-backend error";
465 rs->sr_err = LDAP_OTHER;
472 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
473 rc = backsql_BindParamID( sth, pno + 1 + po,
474 SQL_PARAM_INPUT, &e_id->eid_keyval );
475 if ( rc != SQL_SUCCESS ) {
476 Debug( LDAP_DEBUG_TRACE,
477 " backsql_modify_internal(): "
478 "error binding keyval parameter for %s[%d]\n",
479 at->bam_ad->ad_cname.bv_val, i, 0 );
480 backsql_PrintErrors( bi->sql_db_env, dbh,
482 SQLFreeStmt( sth, SQL_DROP );
484 rs->sr_text = "SQL-backend error";
485 rs->sr_err = LDAP_OTHER;
488 #ifdef BACKSQL_ARBITRARY_KEY
489 Debug( LDAP_DEBUG_TRACE,
490 " backsql_modify_internal(): "
492 pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
493 #else /* ! BACKSQL_ARBITRARY_KEY */
494 Debug( LDAP_DEBUG_TRACE,
495 " backsql_modify_internal(): "
497 pno + 1 + po, e_id->eid_keyval, 0 );
498 #endif /* ! BACKSQL_ARBITRARY_KEY */
501 * check for syntax needed here
502 * maybe need binary bind?
504 rc = backsql_BindParamBerVal( sth, pno + 2 - po,
505 SQL_PARAM_INPUT, at_val );
506 if ( rc != SQL_SUCCESS ) {
507 Debug( LDAP_DEBUG_TRACE,
508 " backsql_modify_internal(): "
509 "error binding value parameter for %s[%d]\n",
510 at->bam_ad->ad_cname.bv_val, i, 0 );
511 backsql_PrintErrors( bi->sql_db_env, dbh,
513 SQLFreeStmt( sth, SQL_DROP );
515 rs->sr_text = "SQL-backend error";
516 rs->sr_err = LDAP_OTHER;
519 Debug( LDAP_DEBUG_TRACE,
520 " backsql_modify_internal(): "
521 "arg%d=\"%s\"; executing \"%s\"\n",
522 pno + 2 - po, at_val->bv_val,
525 rc = SQLExecute( sth );
526 if ( rc != SQL_SUCCESS ) {
527 Debug( LDAP_DEBUG_TRACE,
528 " backsql_modify_internal(): "
529 "add_proc execution failed\n",
531 backsql_PrintErrors( bi->sql_db_env,
534 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
535 SQLFreeStmt( sth, SQL_DROP );
536 rs->sr_err = LDAP_OTHER;
537 rs->sr_text = "SQL-backend error";
541 SQLFreeStmt( sth, SQL_DROP );
545 case LDAP_MOD_DELETE:
546 if ( at->bam_delete_proc == NULL ) {
547 Debug( LDAP_DEBUG_TRACE,
548 " backsql_modify_internal(): "
549 "delete procedure is not defined "
550 "for attribute \"%s\"\n",
551 at->bam_ad->ad_cname.bv_val, 0, 0 );
553 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
554 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
555 rs->sr_text = "operation not permitted "
556 "within namingContext";
563 if ( sm_values == NULL ) {
564 Debug( LDAP_DEBUG_TRACE,
565 " backsql_modify_internal(): "
566 "no values given to delete "
567 "for attribute \"%s\" "
568 "-- deleting all values\n",
569 at->bam_ad->ad_cname.bv_val, 0, 0 );
573 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
574 "deleting values for attribute \"%s\"\n",
575 at->bam_ad->ad_cname.bv_val, 0, 0 );
577 for ( i = 0, at_val = sm_values;
578 !BER_BVISNULL( at_val );
581 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
582 if ( rc != SQL_SUCCESS ) {
583 Debug( LDAP_DEBUG_TRACE,
584 " backsql_modify_internal(): "
585 "error preparing delete query\n",
587 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
589 rs->sr_err = LDAP_OTHER;
590 rs->sr_text = "SQL-backend error";
594 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
596 rc = backsql_BindParamInt( sth, 1,
597 SQL_PARAM_OUTPUT, &prc );
598 if ( rc != SQL_SUCCESS ) {
599 Debug( LDAP_DEBUG_TRACE,
600 " backsql_modify_internal(): "
601 "error binding output parameter for %s[%d]\n",
602 at->bam_ad->ad_cname.bv_val, i, 0 );
603 backsql_PrintErrors( bi->sql_db_env, dbh,
605 SQLFreeStmt( sth, SQL_DROP );
607 rs->sr_text = "SQL-backend error";
608 rs->sr_err = LDAP_OTHER;
615 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
616 rc = backsql_BindParamID( sth, pno + 1 + po,
617 SQL_PARAM_INPUT, &e_id->eid_keyval );
618 if ( rc != SQL_SUCCESS ) {
619 Debug( LDAP_DEBUG_TRACE,
620 " backsql_modify_internal(): "
621 "error binding keyval parameter for %s[%d]\n",
622 at->bam_ad->ad_cname.bv_val, i, 0 );
623 backsql_PrintErrors( bi->sql_db_env, dbh,
625 SQLFreeStmt( sth, SQL_DROP );
627 rs->sr_text = "SQL-backend error";
628 rs->sr_err = LDAP_OTHER;
631 #ifdef BACKSQL_ARBITRARY_KEY
632 Debug( LDAP_DEBUG_TRACE,
633 " backsql_modify_internal(): "
635 pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
636 #else /* ! BACKSQL_ARBITRARY_KEY */
637 Debug( LDAP_DEBUG_TRACE,
638 " backsql_modify_internal(): "
640 pno + 1 + po, e_id->eid_keyval, 0 );
641 #endif /* ! BACKSQL_ARBITRARY_KEY */
644 * check for syntax needed here
645 * maybe need binary bind?
647 rc = backsql_BindParamBerVal( sth, pno + 2 - po,
648 SQL_PARAM_INPUT, at_val );
649 if ( rc != SQL_SUCCESS ) {
650 Debug( LDAP_DEBUG_TRACE,
651 " backsql_modify_internal(): "
652 "error binding value parameter for %s[%d]\n",
653 at->bam_ad->ad_cname.bv_val, i, 0 );
654 backsql_PrintErrors( bi->sql_db_env, dbh,
656 SQLFreeStmt( sth, SQL_DROP );
658 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
659 rs->sr_text = "SQL-backend error";
660 rs->sr_err = LDAP_OTHER;
665 Debug( LDAP_DEBUG_TRACE,
666 " backsql_modify_internal(): "
667 "executing \"%s\"\n",
668 at->bam_delete_proc, 0, 0 );
669 rc = SQLExecute( sth );
670 if ( rc != SQL_SUCCESS ) {
671 Debug( LDAP_DEBUG_TRACE,
672 " backsql_modify_internal(): "
673 "delete_proc execution "
674 "failed\n", 0, 0, 0 );
675 backsql_PrintErrors( bi->sql_db_env,
678 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
679 SQLFreeStmt( sth, SQL_DROP );
680 rs->sr_err = LDAP_OTHER;
681 rs->sr_text = "SQL-backend error";
685 SQLFreeStmt( sth, SQL_DROP );
689 case LDAP_MOD_INCREMENT:
690 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
691 "increment not supported yet\n", 0, 0, 0 );
692 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
693 rs->sr_err = LDAP_OTHER;
694 rs->sr_text = "SQL-backend error";
702 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n",
704 rs->sr_text ? ": " : "",
705 rs->sr_text ? rs->sr_text : "" );
708 * FIXME: should fail in case one change fails?
718 backsql_oc_map_rec *oc,
720 unsigned long new_keyval )
722 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
723 backsql_at_map_rec *at_rec = NULL;
724 struct berval *at_val;
727 /* first parameter #, parameter order */
728 SQLUSMALLINT pno, po;
729 /* procedure return code */
731 SQLUSMALLINT currpos;
734 at_rec = backsql_ad2at( oc, at->a_desc );
736 if ( at_rec == NULL ) {
737 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
738 "attribute \"%s\" is not registered "
739 "in objectclass \"%s\"\n",
740 op->oq_add.rs_e->e_name.bv_val,
741 at->a_desc->ad_cname.bv_val,
742 BACKSQL_OC_NAME( oc ) );
744 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
745 rs->sr_text = "operation not permitted "
746 "within namingContext";
747 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
753 if ( at_rec->bam_add_proc == NULL ) {
754 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
755 "add procedure is not defined "
756 "for attribute \"%s\" "
757 "of structuralObjectClass \"%s\"\n",
758 op->oq_add.rs_e->e_name.bv_val,
759 at->a_desc->ad_cname.bv_val,
760 BACKSQL_OC_NAME( oc ) );
762 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
763 rs->sr_text = "operation not permitted "
764 "within namingContext";
765 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
771 for ( i = 0, at_val = &at->a_vals[ i ];
772 !BER_BVISNULL( at_val );
773 i++, at_val = &at->a_vals[ i ] )
775 char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
778 * Do not deal with the objectClass that is used
781 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
782 if ( dn_match( at_val, &oc->bom_oc->soc_cname ) )
788 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
789 if ( rc != SQL_SUCCESS ) {
791 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
792 rs->sr_text = "SQL-backend error";
793 return rs->sr_err = LDAP_OTHER;
799 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
801 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
802 if ( rc != SQL_SUCCESS ) {
803 Debug( LDAP_DEBUG_TRACE,
804 " backsql_add_attr(): "
805 "error binding output parameter for %s[%d]\n",
806 at_rec->bam_ad->ad_cname.bv_val, i, 0 );
807 backsql_PrintErrors( bi->sql_db_env, dbh,
809 SQLFreeStmt( sth, SQL_DROP );
811 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
812 rs->sr_text = "SQL-backend error";
813 return rs->sr_err = LDAP_OTHER;
823 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
824 currpos = pno + 1 + po;
825 rc = backsql_BindParamInt( sth, currpos,
826 SQL_PARAM_INPUT, &new_keyval );
827 if ( rc != SQL_SUCCESS ) {
828 Debug( LDAP_DEBUG_TRACE,
829 " backsql_add_attr(): "
830 "error binding keyval parameter for %s[%d]\n",
831 at_rec->bam_ad->ad_cname.bv_val, i, 0 );
832 backsql_PrintErrors( bi->sql_db_env, dbh,
834 SQLFreeStmt( sth, SQL_DROP );
836 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
837 rs->sr_text = "SQL-backend error";
838 return rs->sr_err = LDAP_OTHER;
844 currpos = pno + 2 - po;
847 * check for syntax needed here
848 * maybe need binary bind?
851 rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val );
852 if ( rc != SQL_SUCCESS ) {
853 Debug( LDAP_DEBUG_TRACE,
854 " backsql_add_attr(): "
855 "error binding value parameter for %s[%d]\n",
856 at_rec->bam_ad->ad_cname.bv_val, i, 0 );
857 backsql_PrintErrors( bi->sql_db_env, dbh,
859 SQLFreeStmt( sth, SQL_DROP );
861 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
862 rs->sr_text = "SQL-backend error";
863 return rs->sr_err = LDAP_OTHER;
870 snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=%lu",
872 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
873 "executing \"%s\" %s\n",
874 op->oq_add.rs_e->e_name.bv_val,
875 at_rec->bam_add_proc, logbuf );
877 rc = SQLExecute( sth );
878 if ( rc != SQL_SUCCESS ) {
879 Debug( LDAP_DEBUG_TRACE,
880 " backsql_add_attr(\"%s\"): "
881 "add_proc execution failed\n",
882 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
883 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
885 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
886 SQLFreeStmt( sth, SQL_DROP );
887 rs->sr_text = "SQL-backend error";
888 return rs->sr_err = LDAP_OTHER;
891 SQLFreeStmt( sth, SQL_DROP );
898 backsql_add( Operation *op, SlapReply *rs )
900 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
903 unsigned long new_keyval = 0;
905 backsql_oc_map_rec *oc = NULL;
906 backsql_entryID parent_id = BACKSQL_ENTRYID_INIT;
909 *at_objectClass = NULL;
911 struct berval realdn = BER_BVNULL;
913 #ifdef BACKSQL_SYNCPROV
915 * NOTE: fake successful result to force contextCSN to be bumped up
918 char buf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
919 struct berval csn = BER_BVNULL;
921 slap_get_csn( op, buf, sizeof( buf ), &csn, 1 );
923 rs->sr_err = LDAP_SUCCESS;
924 send_ldap_result( op, rs );
926 slap_graduate_commit_csn( op );
930 #endif /* BACKSQL_SYNCPROV */
932 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
933 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
936 if ( global_schemacheck ) {
937 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
939 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
941 &rs->sr_text, textbuf, sizeof( textbuf ) );
942 if ( rs->sr_err != LDAP_SUCCESS ) {
943 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
944 "entry failed schema check -- aborting\n",
945 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
950 /* search structural objectClass */
951 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
952 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
957 /* there must exist */
958 assert( at != NULL );
960 /* I guess we should play with sub/supertypes to find a suitable oc */
961 oc = backsql_name2oc( bi, &at->a_vals[0] );
964 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
965 "cannot map structuralObjectClass \"%s\" -- aborting\n",
966 op->oq_add.rs_e->e_name.bv_val,
967 at->a_vals[0].bv_val, 0 );
968 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
969 rs->sr_text = "operation not permitted within namingContext";
973 if ( oc->bom_create_proc == NULL ) {
974 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
975 "create procedure is not defined "
976 "for structuralObjectClass \"%s\" - aborting\n",
977 op->oq_add.rs_e->e_name.bv_val,
978 at->a_vals[0].bv_val, 0 );
979 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
980 rs->sr_text = "operation not permitted within namingContext";
983 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
984 && oc->bom_create_keyval == NULL ) {
985 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
986 "create procedure needs select procedure, "
987 "but none is defined for structuralObjectClass \"%s\" "
989 op->oq_add.rs_e->e_name.bv_val,
990 at->a_vals[0].bv_val, 0 );
991 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
992 rs->sr_text = "operation not permitted within namingContext";
996 rs->sr_err = backsql_get_db_conn( op, &dbh );
997 if ( rs->sr_err != LDAP_SUCCESS ) {
998 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
999 "could not get connection handle - exiting\n",
1000 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1001 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
1002 ? "SQL-backend error" : NULL;
1007 * Check if entry exists
1009 realdn = op->oq_add.rs_e->e_name;
1010 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
1011 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1012 "backsql_api_dn2odbc(\"%s\") failed\n",
1013 op->oq_add.rs_e->e_name.bv_val, realdn.bv_val, 0 );
1014 rs->sr_err = LDAP_OTHER;
1015 rs->sr_text = "SQL-backend error";
1019 rs->sr_err = backsql_dn2id( op, rs, NULL, dbh, &realdn, 0 );
1020 if ( rs->sr_err == LDAP_SUCCESS ) {
1021 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1023 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1024 rs->sr_err = LDAP_ALREADY_EXISTS;
1029 * Get the parent dn and see if the corresponding entry exists.
1031 if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
1032 pdn = slap_empty_bv;
1035 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
1038 rs->sr_err = backsql_dn2id( op, rs, &parent_id, dbh, &pdn, 1 );
1039 if ( rs->sr_err != LDAP_SUCCESS ) {
1040 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1041 "could not lookup parent entry for new record \"%s\"\n",
1042 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
1044 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1050 * if not attempting to add entry at suffix or with parent ""
1052 if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
1053 || !BER_BVISEMPTY( &pdn ) ) && !is_entry_glue( op->oq_add.rs_e )
1054 && !BACKSQL_ALLOW_ORPHANS( bi ) )
1056 Debug( LDAP_DEBUG_TRACE, " backsql_add: %s denied\n",
1057 BER_BVISEMPTY( &pdn ) ? "suffix" : "entry at root",
1064 char *matched = NULL;
1067 dnParent( &dn, &pdn );
1070 * Empty DN ("") defaults to LDAP_SUCCESS
1072 rs->sr_err = backsql_dn2id( op, rs, NULL, dbh, &pdn, 1 );
1073 switch ( rs->sr_err ) {
1074 case LDAP_NO_SUCH_OBJECT:
1075 if ( !BER_BVISEMPTY( &pdn ) ) {
1078 /* fail over to next case */
1081 matched = pdn.bv_val;
1082 /* fail over to next case */
1085 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1086 rs->sr_matched = matched;
1092 #ifdef BACKSQL_ARBITRARY_KEY
1093 ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
1094 #else /* ! BACKSQL_ARBITRARY_KEY */
1095 parent_id.eid_id = 0;
1096 #endif /* ! BACKSQL_ARBITRARY_KEY */
1097 rs->sr_err = LDAP_SUCCESS;
1101 /* check "children" pseudo-attribute access to parent */
1104 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
1105 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
1106 NULL, ACL_WRITE, NULL ) ) {
1107 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1112 * create_proc is executed; if expect_return is set, then
1113 * an output parameter is bound, which should contain
1114 * the id of the added row; otherwise the procedure
1115 * is expected to return the id as the first column of a select
1118 rc = SQLAllocStmt( dbh, &sth );
1119 if ( rc != SQL_SUCCESS ) {
1120 rs->sr_err = LDAP_OTHER;
1121 rs->sr_text = "SQL-backend error";
1125 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1126 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval );
1127 if ( rc != SQL_SUCCESS ) {
1128 Debug( LDAP_DEBUG_TRACE,
1129 " backsql_add_attr(): "
1130 "error binding keyval parameter for objectClass %s\n",
1131 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1132 backsql_PrintErrors( bi->sql_db_env, dbh,
1134 SQLFreeStmt( sth, SQL_DROP );
1136 rs->sr_text = "SQL-backend error";
1137 rs->sr_err = LDAP_OTHER;
1142 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n",
1143 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
1144 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
1145 if ( rc != SQL_SUCCESS ) {
1146 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1147 "create_proc execution failed\n",
1148 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1149 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1150 SQLFreeStmt( sth, SQL_DROP );
1151 rs->sr_err = LDAP_OTHER;
1152 rs->sr_text = "SQL-backend error";
1157 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1160 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1162 SQLINTEGER value_len;
1164 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1165 SQLFreeStmt( sth, SQL_DROP );
1166 rc = SQLAllocStmt( dbh, &sth );
1167 if ( rc != SQL_SUCCESS ) {
1168 rs->sr_err = LDAP_OTHER;
1169 rs->sr_text = "SQL-backend error";
1173 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
1174 if ( rc != SQL_SUCCESS ) {
1175 rs->sr_err = LDAP_OTHER;
1176 rs->sr_text = "SQL-backend error";
1182 * the query to know the id of the inserted entry
1183 * must be embedded in the create procedure
1185 rc = SQLNumResultCols( sth, &ncols );
1186 if ( rc != SQL_SUCCESS ) {
1187 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1188 "create_proc result evaluation failed\n",
1189 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1190 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1191 SQLFreeStmt( sth, SQL_DROP );
1192 rs->sr_err = LDAP_OTHER;
1193 rs->sr_text = "SQL-backend error";
1196 } else if ( ncols != 1 ) {
1197 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1198 "create_proc result is bogus (ncols=%d)\n",
1199 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
1200 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1201 SQLFreeStmt( sth, SQL_DROP );
1202 rs->sr_err = LDAP_OTHER;
1203 rs->sr_text = "SQL-backend error";
1209 SQLCHAR colname[ 64 ];
1210 SQLSMALLINT name_len, col_type, col_scale, col_null;
1214 * FIXME: check whether col_type is compatible,
1215 * if it can be null and so on ...
1217 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
1219 (SQLUINTEGER)( sizeof( colname ) - 1 ),
1220 &name_len, &col_type,
1221 &col_prec, &col_scale, &col_null );
1225 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1226 (SQLPOINTER)&new_keyval,
1227 (SQLINTEGER)sizeof( new_keyval ),
1230 rc = SQLFetch( sth );
1232 if ( value_len <= 0 ) {
1233 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1234 "create_proc result is empty?\n",
1235 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1236 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1237 SQLFreeStmt( sth, SQL_DROP );
1238 rs->sr_err = LDAP_OTHER;
1239 rs->sr_text = "SQL-backend error";
1244 SQLFreeStmt( sth, SQL_DROP );
1246 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1247 "create_proc returned keyval=%ld\n",
1248 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
1250 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
1251 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
1252 "adding attribute \"%s\"\n",
1253 at->a_desc->ad_cname.bv_val, 0, 0 );
1257 * - the first occurrence of objectClass, which is used
1258 * to determine how to build the SQL entry (FIXME ?!?)
1259 * - operational attributes
1260 * - empty attributes (FIXME ?!?)
1262 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1266 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1267 at_objectClass = at;
1271 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
1272 if ( rs->sr_err != LDAP_SUCCESS ) {
1277 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_query, 0 );
1278 if ( rc != SQL_SUCCESS ) {
1279 rs->sr_err = LDAP_OTHER;
1280 rs->sr_text = "SQL-backend error";
1284 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn );
1285 if ( rc != SQL_SUCCESS ) {
1286 Debug( LDAP_DEBUG_TRACE,
1287 " backsql_add_attr(): "
1288 "error binding DN parameter for objectClass %s\n",
1289 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1290 backsql_PrintErrors( bi->sql_db_env, dbh,
1292 SQLFreeStmt( sth, SQL_DROP );
1294 rs->sr_text = "SQL-backend error";
1295 rs->sr_err = LDAP_OTHER;
1299 rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id );
1300 if ( rc != SQL_SUCCESS ) {
1301 Debug( LDAP_DEBUG_TRACE,
1302 " backsql_add_attr(): "
1303 "error binding objectClass ID parameter for objectClass %s\n",
1304 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1305 backsql_PrintErrors( bi->sql_db_env, dbh,
1307 SQLFreeStmt( sth, SQL_DROP );
1309 rs->sr_text = "SQL-backend error";
1310 rs->sr_err = LDAP_OTHER;
1314 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &parent_id.eid_id );
1315 if ( rc != SQL_SUCCESS ) {
1316 Debug( LDAP_DEBUG_TRACE,
1317 " backsql_add_attr(): "
1318 "error binding parent ID parameter for objectClass %s\n",
1319 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1320 backsql_PrintErrors( bi->sql_db_env, dbh,
1322 SQLFreeStmt( sth, SQL_DROP );
1324 rs->sr_text = "SQL-backend error";
1325 rs->sr_err = LDAP_OTHER;
1329 rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval );
1330 if ( rc != SQL_SUCCESS ) {
1331 Debug( LDAP_DEBUG_TRACE,
1332 " backsql_add_attr(): "
1333 "error binding entry ID parameter for objectClass %s\n",
1334 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1335 backsql_PrintErrors( bi->sql_db_env, dbh,
1337 SQLFreeStmt( sth, SQL_DROP );
1339 rs->sr_text = "SQL-backend error";
1340 rs->sr_err = LDAP_OTHER;
1344 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
1345 bi->sql_insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1346 #ifdef BACKSQL_ARBITRARY_KEY
1347 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1348 "parent_id=%s, keyval=%ld\n",
1349 oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1350 #else /* ! BACKSQL_ARBITRARY_KEY */
1351 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1352 "parent_id=%ld, keyval=%ld\n",
1353 oc->bom_id, parent_id.eid_id, new_keyval );
1354 #endif /* ! BACKSQL_ARBITRARY_KEY */
1355 rc = SQLExecute( sth );
1356 if ( rc != SQL_SUCCESS ) {
1357 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1358 "could not insert ldap_entries record\n",
1359 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1360 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
1363 * execute delete_proc to delete data added !!!
1365 SQLFreeStmt( sth, SQL_DROP );
1366 rs->sr_err = LDAP_OTHER;
1367 rs->sr_text = "SQL-backend error";
1371 /* FIXME: need ldap_entries.id of newly added entry */
1372 if ( at_objectClass ) {
1373 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at_objectClass, new_keyval );
1374 if ( rs->sr_err != LDAP_SUCCESS ) {
1379 SQLFreeStmt( sth, SQL_DROP );
1383 * Commit only if all operations succeed
1385 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
1386 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1389 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1393 * FIXME: NOOP does not work for add -- it works for all
1394 * the other operations, and I don't get the reason :(
1396 * hint: there might be some autocommit in Postgres
1397 * so that when the unique id of the key table is
1398 * automatically increased, there's no rollback.
1399 * We might implement a "rollback" procedure consisting
1400 * in deleting that row.
1403 send_ldap_result( op, rs );
1405 if ( !BER_BVISNULL( &realdn )
1406 && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
1408 ch_free( realdn.bv_val );
1410 if ( !BER_BVISNULL( &parent_id.eid_ndn ) ) {
1411 (void)backsql_free_entryID( &parent_id, 0 );
1414 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1415 op->oq_add.rs_e->e_name.bv_val,
1417 rs->sr_text ? rs->sr_text : "" );
1419 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );