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 && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
44 || is_at_operational( (ad)->ad_type ) \
45 || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
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 );
294 /* LDAP_MOD_DELETE gets here if all values must be deleted */
295 if ( c_mod->sm_op == LDAP_MOD_DELETE ) {
301 * PASSTHROUGH - to add new attributes -- do NOT add break
304 case SLAP_MOD_SOFTADD:
306 if ( at->bam_add_proc == NULL ) {
307 Debug( LDAP_DEBUG_TRACE,
308 " backsql_modify_internal(): "
309 "add procedure is not defined "
310 "for attribute \"%s\"\n",
311 at->bam_ad->ad_cname.bv_val, 0, 0 );
313 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
314 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
315 rs->sr_text = "operation not permitted "
316 "within namingContext";
323 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
324 "adding new values for attribute \"%s\"\n",
325 at->bam_ad->ad_cname.bv_val, 0, 0 );
326 for ( i = 0, at_val = c_mod->sm_values;
327 at_val->bv_val != NULL;
330 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
331 if ( rc != SQL_SUCCESS ) {
332 Debug( LDAP_DEBUG_TRACE,
333 " backsql_modify_internal(): "
334 "error preparing add query\n",
336 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
338 rs->sr_err = LDAP_OTHER;
339 rs->sr_text = "SQL-backend error";
343 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
345 SQLBindParameter( sth, 1,
347 SQL_C_ULONG, SQL_INTEGER,
352 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
353 #ifdef BACKSQL_ARBITRARY_KEY
354 SQLBindParameter( sth, pno + 1 + po,
356 SQL_C_CHAR, SQL_VARCHAR,
357 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
358 #else /* ! BACKSQL_ARBITRARY_KEY */
359 SQLBindParameter( sth, pno + 1 + po,
361 SQL_C_ULONG, SQL_INTEGER,
362 0, 0, &e_id->eid_keyval, 0, 0 );
363 #endif /* ! BACKSQL_ARBITRARY_KEY */
366 * check for syntax needed here
367 * maybe need binary bind?
369 SQLBindParameter( sth, pno + 2 - po,
371 SQL_C_CHAR, SQL_CHAR,
372 0, 0, at_val->bv_val,
375 Debug( LDAP_DEBUG_TRACE,
376 " backsql_modify_internal(): "
377 "executing \"%s\"\n",
378 at->bam_add_proc, 0, 0 );
379 rc = SQLExecute( sth );
380 if ( rc != SQL_SUCCESS ) {
381 Debug( LDAP_DEBUG_TRACE,
382 " backsql_modify_internal(): "
383 "add_proc execution failed\n",
385 backsql_PrintErrors( bi->db_env,
388 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
389 rs->sr_err = LDAP_OTHER;
390 rs->sr_text = "SQL-backend error";
394 #ifdef BACKSQL_REALLOC_STMT
395 SQLFreeStmt( sth, SQL_DROP );
396 SQLAllocStmt( dbh, &sth );
397 #endif /* BACKSQL_REALLOC_STMT */
401 case LDAP_MOD_DELETE:
402 if ( at->bam_delete_proc == NULL ) {
403 Debug( LDAP_DEBUG_TRACE,
404 " backsql_modify_internal(): "
405 "delete procedure is not defined "
406 "for attribute \"%s\"\n",
407 at->bam_ad->ad_cname.bv_val, 0, 0 );
409 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
410 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
411 rs->sr_text = "operation not permitted "
412 "within namingContext";
419 if ( c_mod->sm_values == NULL ) {
420 Debug( LDAP_DEBUG_TRACE,
421 " backsql_modify_internal(): "
422 "no values given to delete "
423 "for attribute \"%s\" "
424 "-- deleting all values\n",
425 at->bam_ad->ad_cname.bv_val, 0, 0 );
429 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
430 "deleting values for attribute \"%s\"\n",
431 at->bam_ad->ad_cname.bv_val, 0, 0 );
433 for ( i = 0, at_val = c_mod->sm_values;
434 at_val->bv_val != NULL;
436 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
438 SQLBindParameter( sth, 1,
440 SQL_C_ULONG, SQL_INTEGER,
445 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
446 #ifdef BACKSQL_ARBITRARY_KEY
447 SQLBindParameter( sth, pno + 1 + po,
449 SQL_C_CHAR, SQL_VARCHAR,
450 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
451 #else /* ! BACKSQL_ARBITRARY_KEY */
452 SQLBindParameter( sth, pno + 1 + po,
454 SQL_C_ULONG, SQL_INTEGER,
455 0, 0, &e_id->eid_keyval, 0, 0 );
456 #endif /* ! BACKSQL_ARBITRARY_KEY */
459 * check for syntax needed here
460 * maybe need binary bind?
462 SQLBindParameter( sth, pno + 2 - po,
463 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
464 0, 0, at_val->bv_val,
467 Debug( LDAP_DEBUG_TRACE,
468 " backsql_modify_internal(): "
469 "executing \"%s\"\n",
470 at->bam_delete_proc, 0, 0 );
471 rc = SQLExecDirect( sth, at->bam_delete_proc,
473 if ( rc != SQL_SUCCESS ) {
474 Debug( LDAP_DEBUG_TRACE,
475 " backsql_modify_internal(): "
476 "delete_proc execution "
477 "failed\n", 0, 0, 0 );
478 backsql_PrintErrors( bi->db_env,
481 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
482 rs->sr_err = LDAP_OTHER;
483 rs->sr_text = "SQL-backend error";
487 #ifdef BACKSQL_REALLOC_STMT
488 SQLFreeStmt( sth, SQL_DROP );
489 SQLAllocStmt( dbh, &sth );
490 #endif /* BACKSQL_REALLOC_STMT */
494 #ifndef BACKSQL_REALLOC_STMT
495 SQLFreeStmt( sth, SQL_RESET_PARAMS );
496 #else /* BACKSQL_REALLOC_STMT */
497 SQLFreeStmt( sth, SQL_DROP );
498 #endif /* BACKSQL_REALLOC_STMT */
503 #ifndef BACKSQL_REALLOC_STMT
504 SQLFreeStmt( sth, SQL_DROP );
505 #endif /* BACKSQL_REALLOC_STMT */
507 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
508 rs->sr_err, rs->sr_text ? ": " : "",
509 rs->sr_text ? rs->sr_text : "" );
512 * FIXME: should fail in case one change fails?
523 backsql_oc_map_rec *oc,
525 unsigned long new_keyval )
527 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
528 backsql_at_map_rec *at_rec = NULL;
529 struct berval *at_val;
532 /* first parameter #, parameter order */
533 SQLUSMALLINT pno, po;
534 /* procedure return code */
536 SQLUSMALLINT currpos;
538 at_rec = backsql_ad2at( oc, at->a_desc );
540 if ( at_rec == NULL ) {
541 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
542 "attribute \"%s\" is not registered "
543 "in objectclass \"%s\"\n",
544 op->oq_add.rs_e->e_name.bv_val,
545 at->a_desc->ad_cname.bv_val,
546 BACKSQL_OC_NAME( oc ) );
548 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
549 rs->sr_text = "operation not permitted "
550 "within namingContext";
551 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
557 if ( at_rec->bam_add_proc == NULL ) {
558 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
559 "add procedure is not defined "
560 "for attribute \"%s\" "
561 "of structuralObjectClass \"%s\"\n",
562 op->oq_add.rs_e->e_name.bv_val,
563 at->a_desc->ad_cname.bv_val,
564 BACKSQL_OC_NAME( oc ) );
566 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
567 rs->sr_text = "operation not permitted "
568 "within namingContext";
569 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
575 for ( i = 0, at_val = &at->a_vals[ i ];
576 at_val->bv_val != NULL;
577 i++, at_val = &at->a_vals[ i ] )
579 char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
582 * Do not deal with the objectClass that is used
585 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
586 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) )
592 #ifdef BACKSQL_REALLOC_STMT
593 rc = backsql_Prepare( dbh, sth, at_rec->bam_add_proc, 0 );
594 if ( rc != SQL_SUCCESS ) {
596 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
597 rs->sr_text = "SQL-backend error";
598 return rs->sr_err = LDAP_OTHER;
603 #endif /* BACKSQL_REALLOC_STMT */
605 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
607 SQLBindParameter( *sth, 1, SQL_PARAM_OUTPUT,
608 SQL_C_ULONG, SQL_INTEGER,
614 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
615 currpos = pno + 1 + po;
616 SQLBindParameter( *sth, currpos,
617 SQL_PARAM_INPUT, SQL_C_ULONG,
618 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
619 currpos = pno + 2 - po;
622 * check for syntax needed here
623 * maybe need binary bind?
626 backsql_BindParamStr( *sth, currpos,
627 at_val->bv_val, at_val->bv_len + 1 );
630 snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
632 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
633 "executing \"%s\" %s\n",
634 op->oq_add.rs_e->e_name.bv_val,
635 at_rec->bam_add_proc, logbuf );
637 #ifndef BACKSQL_REALLOC_STMT
638 rc = SQLExecDirect( *sth, at_rec->bam_add_proc, SQL_NTS );
639 #else /* BACKSQL_REALLOC_STMT */
640 rc = SQLExecute( *sth );
641 #endif /* BACKSQL_REALLOC_STMT */
642 if ( rc != SQL_SUCCESS ) {
643 Debug( LDAP_DEBUG_TRACE,
644 " backsql_add(\"%s\"): "
645 "add_proc execution failed\n",
646 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
647 backsql_PrintErrors( bi->db_env, dbh, *sth, rc );
649 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
650 rs->sr_text = "SQL-backend error";
651 return rs->sr_err = LDAP_OTHER;
654 #ifndef BACKSQL_REALLOC_STMT
655 SQLFreeStmt( *sth, SQL_RESET_PARAMS );
656 #else /* BACKSQL_REALLOC_STMT */
657 SQLFreeStmt( *sth, SQL_DROP );
658 #endif /* BACKSQL_REALLOC_STMT */
665 backsql_add( Operation *op, SlapReply *rs )
667 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
670 unsigned long new_keyval = 0;
673 backsql_oc_map_rec *oc = NULL;
674 backsql_at_map_rec *at_rec = NULL;
675 backsql_entryID parent_id = BACKSQL_ENTRYID_INIT;
678 *at_objectClass = NULL;
679 struct berval *at_val;
681 /* first parameter #, parameter order */
682 SQLUSMALLINT pno, po;
683 /* procedure return code */
685 struct berval realdn = BER_BVNULL,
686 realpdn = BER_BVNULL;
688 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
689 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
692 if ( global_schemacheck ) {
693 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
695 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
697 &rs->sr_text, textbuf, sizeof( textbuf ) );
698 if ( rs->sr_err != LDAP_SUCCESS ) {
699 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
700 "entry failed schema check -- aborting\n",
701 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
706 /* search structural objectClass */
707 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
708 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
713 /* there must exist */
714 assert( at != NULL );
716 /* I guess we should play with sub/supertypes to find a suitable oc */
717 oc = backsql_name2oc( bi, &at->a_vals[0] );
720 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
721 "cannot map structuralObjectClass \"%s\" -- aborting\n",
722 op->oq_add.rs_e->e_name.bv_val,
723 at->a_vals[0].bv_val, 0 );
724 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
725 rs->sr_text = "operation not permitted within namingContext";
729 if ( oc->bom_create_proc == NULL ) {
730 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
731 "create procedure is not defined "
732 "for structuralObjectClass \"%s\" - aborting\n",
733 op->oq_add.rs_e->e_name.bv_val,
734 at->a_vals[0].bv_val, 0 );
735 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
736 rs->sr_text = "operation not permitted within namingContext";
739 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
740 && oc->bom_create_keyval == NULL ) {
741 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
742 "create procedure needs select procedure, "
743 "but none is defined for structuralObjectClass \"%s\" "
745 op->oq_add.rs_e->e_name.bv_val,
746 at->a_vals[0].bv_val, 0 );
747 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
748 rs->sr_text = "operation not permitted within namingContext";
752 rs->sr_err = backsql_get_db_conn( op, &dbh );
753 if ( rs->sr_err != LDAP_SUCCESS ) {
754 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
755 "could not get connection handle - exiting\n",
756 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
757 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
758 ? "SQL-backend error" : NULL;
763 * Check if entry exists
765 realdn = op->oq_add.rs_e->e_name;
766 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
767 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
768 "backsql_api_dn2odbc(\"%s\") failed\n",
769 op->oq_add.rs_e->e_name.bv_val,
770 op->oq_add.rs_e->e_name.bv_val, 0 );
771 rs->sr_err = LDAP_OTHER;
772 rs->sr_text = "SQL-backend error";
776 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
777 if ( rs->sr_err == LDAP_SUCCESS ) {
778 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
780 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
781 rs->sr_err = LDAP_ALREADY_EXISTS;
786 * Get the parent dn and see if the corresponding entry exists.
788 if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
791 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
795 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
796 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
797 "backsql_api_dn2odbc(\"%s\") failed\n",
798 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
799 rs->sr_err = LDAP_OTHER;
800 rs->sr_text = "SQL-backend error";
804 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
805 if ( rs->sr_err != LDAP_SUCCESS ) {
806 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
807 "could not lookup parent entry for new record \"%s\"\n",
808 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
810 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
816 * if not attempting to add entry at suffix or with parent ""
818 if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
819 || pdn.bv_len > 0 ) && !is_entry_glue( op->oq_add.rs_e ) )
821 Debug( LDAP_DEBUG_TRACE, " backsql_add: %s denied\n",
822 pdn.bv_len == 0 ? "suffix" : "entry at root",
829 char *matched = NULL;
831 if ( realpdn.bv_val != pdn.bv_val ) {
832 ch_free( realpdn.bv_val );
836 dnParent( &dn, &pdn );
839 * Empty DN ("") defaults to LDAP_SUCCESS
842 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
843 Debug( LDAP_DEBUG_TRACE,
844 " backsql_add(\"%s\"): "
845 "backsql_api_dn2odbc failed\n",
846 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
847 rs->sr_err = LDAP_OTHER;
848 rs->sr_text = "SQL-backend error";
852 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
853 switch ( rs->sr_err ) {
854 case LDAP_NO_SUCH_OBJECT:
855 if ( pdn.bv_len > 0 ) {
858 /* fail over to next case */
861 matched = pdn.bv_val;
862 /* fail over to next case */
865 rs->sr_err = LDAP_NO_SUCH_OBJECT;
866 rs->sr_matched = matched;
872 #ifdef BACKSQL_ARBITRARY_KEY
873 ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
874 #else /* ! BACKSQL_ARBITRARY_KEY */
875 parent_id.eid_id = 0;
876 #endif /* ! BACKSQL_ARBITRARY_KEY */
877 rs->sr_err = LDAP_SUCCESS;
881 /* check "children" pseudo-attribute access to parent */
884 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
885 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
886 NULL, ACL_WRITE, NULL ) ) {
887 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
892 * create_proc is executed; if expect_return is set, then
893 * an output parameter is bound, which should contain
894 * the id of the added row; otherwise the procedure
895 * is expected to return the id as the first column of a select
898 rc = SQLAllocStmt( dbh, &sth );
899 if ( rc != SQL_SUCCESS ) {
900 rs->sr_err = LDAP_OTHER;
901 rs->sr_text = "SQL-backend error";
905 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
906 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
907 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
910 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n",
911 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
912 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
913 if ( rc != SQL_SUCCESS ) {
914 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
915 "create_proc execution failed\n",
916 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
917 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
918 SQLFreeStmt( sth, SQL_DROP );
919 rs->sr_err = LDAP_OTHER;
920 rs->sr_text = "SQL-backend error";
924 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
927 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
929 SQLINTEGER value_len;
931 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
932 #ifndef BACKSQL_REALLOC_STMT
933 SQLFreeStmt( sth, SQL_RESET_PARAMS );
934 #else /* BACKSQL_REALLOC_STMT */
935 SQLFreeStmt( sth, SQL_DROP );
936 rc = SQLAllocStmt( dbh, &sth );
937 if ( rc != SQL_SUCCESS ) {
938 rs->sr_err = LDAP_OTHER;
939 rs->sr_text = "SQL-backend error";
942 #endif /* BACKSQL_REALLOC_STMT */
944 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
945 if ( rc != SQL_SUCCESS ) {
946 rs->sr_err = LDAP_OTHER;
947 rs->sr_text = "SQL-backend error";
953 * the query to know the id of the inserted entry
954 * must be embedded in the create procedure
956 rc = SQLNumResultCols( sth, &ncols );
957 if ( rc != SQL_SUCCESS ) {
958 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
959 "create_proc result evaluation failed\n",
960 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
961 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
962 SQLFreeStmt( sth, SQL_DROP );
963 rs->sr_err = LDAP_OTHER;
964 rs->sr_text = "SQL-backend error";
967 } else if ( ncols != 1 ) {
968 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
969 "create_proc result is bogus (ncols=%d)\n",
970 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
971 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
972 SQLFreeStmt( sth, SQL_DROP );
973 rs->sr_err = LDAP_OTHER;
974 rs->sr_text = "SQL-backend error";
980 SQLCHAR colname[ 64 ];
981 SQLSMALLINT name_len, col_type, col_scale, col_null;
985 * FIXME: check whether col_type is compatible,
986 * if it can be null and so on ...
988 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
990 (SQLUINTEGER)( sizeof( colname ) - 1 ),
991 &name_len, &col_type,
992 &col_prec, &col_scale, &col_null );
996 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
997 (SQLPOINTER)&new_keyval,
998 (SQLINTEGER)sizeof( new_keyval ),
1001 rc = SQLFetch( sth );
1003 if ( value_len <= 0 ) {
1004 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1005 "create_proc result is empty?\n",
1006 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1007 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1008 SQLFreeStmt( sth, SQL_DROP );
1009 rs->sr_err = LDAP_OTHER;
1010 rs->sr_text = "SQL-backend error";
1015 #ifndef BACKSQL_REALLOC_STMT
1016 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1017 #else /* BACKSQL_REALLOC_STMT */
1018 SQLFreeStmt( sth, SQL_DROP );
1019 #endif /* BACKSQL_REALLOC_STMT */
1021 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1022 "create_proc returned keyval=%ld\n",
1023 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
1025 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
1026 SQLUSMALLINT currpos;
1028 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
1029 "adding attribute \"%s\"\n",
1030 at->a_desc->ad_cname.bv_val, 0, 0 );
1034 * - the first occurrence of objectClass, which is used
1035 * to determine how to build the SQL entry (FIXME ?!?)
1036 * - operational attributes
1037 * - empty attributes (FIXME ?!?)
1039 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1043 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1044 at_objectClass = at;
1048 rs->sr_err = backsql_add_attr( op, rs, dbh, &sth, oc, at, new_keyval );
1049 if ( rs->sr_err != LDAP_SUCCESS ) {
1054 #ifdef BACKSQL_REALLOC_STMT
1055 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1056 if ( rc != SQL_SUCCESS ) {
1057 rs->sr_err = LDAP_OTHER;
1058 rs->sr_text = "SQL-backend error";
1061 #endif /* BACKSQL_REALLOC_STMT */
1063 backsql_BindParamStr( sth, 1, realdn.bv_val, BACKSQL_MAX_DN_LEN );
1064 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1065 0, 0, &oc->bom_id, 0, 0 );
1066 #ifdef BACKSQL_ARBITRARY_KEY
1067 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
1068 0, 0, parent_id.eid_id.bv_val, 0, 0 );
1069 #else /* ! BACKSQL_ARBITRARY_KEY */
1070 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1071 0, 0, &parent_id.eid_id, 0, 0 );
1072 #endif /* ! BACKSQL_ARBITRARY_KEY */
1073 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1074 0, 0, &new_keyval, 0, 0 );
1076 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
1077 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1078 #ifdef BACKSQL_ARBITRARY_KEY
1079 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1080 "parent_id=%s, keyval=%ld\n",
1081 oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1082 #else /* ! BACKSQL_ARBITRARY_KEY */
1083 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1084 "parent_id=%ld, keyval=%ld\n",
1085 oc->bom_id, parent_id.eid_id, new_keyval );
1086 #endif /* ! BACKSQL_ARBITRARY_KEY */
1087 #ifndef BACKSQL_REALLOC_STMT
1088 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1089 #else /* BACKSQL_REALLOC_STMT */
1090 rc = SQLExecute( sth );
1091 #endif /* BACKSQL_REALLOC_STMT */
1092 if ( rc != SQL_SUCCESS ) {
1093 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1094 "could not insert ldap_entries record\n",
1095 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1096 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1099 * execute delete_proc to delete data added !!!
1101 SQLFreeStmt( sth, SQL_DROP );
1102 rs->sr_err = LDAP_OTHER;
1103 rs->sr_text = "SQL-backend error";
1107 /* FIXME: need ldap_entries.id of newly added entry */
1108 if ( at_objectClass ) {
1109 rs->sr_err = backsql_add_attr( op, rs, dbh, &sth, oc, at_objectClass, new_keyval );
1110 if ( rs->sr_err != LDAP_SUCCESS ) {
1115 SQLFreeStmt( sth, SQL_DROP );
1119 * Commit only if all operations succeed
1121 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
1122 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1124 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1129 * FIXME: NOOP does not work for add -- it works for all
1130 * the other operations, and I don't get the reason :(
1132 * hint: there might be some autocommit in Postgres
1133 * so that when the unique id of the key table is
1134 * automatically increased, there's no rollback.
1135 * We might implement a "rollback" procedure consisting
1136 * in deleting that row.
1139 send_ldap_result( op, rs );
1141 if ( !BER_BVISNULL( &realdn )
1142 && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
1144 ch_free( realdn.bv_val );
1146 if ( !BER_BVISNULL( &realpdn ) && realpdn.bv_val != pdn.bv_val ) {
1147 ch_free( realpdn.bv_val );
1149 if ( !BER_BVISNULL( &parent_id.eid_dn ) ) {
1150 backsql_free_entryID( &parent_id, 0 );
1153 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1154 op->oq_add.rs_e->e_name.bv_val,
1156 rs->sr_text ? rs->sr_text : "" );
1158 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1161 #endif /* SLAPD_SQL */