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;
325 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
326 if ( rc != SQL_SUCCESS ) {
327 Debug( LDAP_DEBUG_TRACE,
328 " backsql_modify_internal(): "
329 "error preparing add query\n",
331 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
333 rs->sr_err = LDAP_OTHER;
334 rs->sr_text = "SQL-backend error";
338 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
340 SQLBindParameter( sth, 1,
342 SQL_C_ULONG, SQL_INTEGER,
347 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
348 #ifdef BACKSQL_ARBITRARY_KEY
349 SQLBindParameter( sth, pno + 1 + po,
351 SQL_C_CHAR, SQL_VARCHAR,
352 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
353 #else /* ! BACKSQL_ARBITRARY_KEY */
354 SQLBindParameter( sth, pno + 1 + po,
356 SQL_C_ULONG, SQL_INTEGER,
357 0, 0, &e_id->eid_keyval, 0, 0 );
358 #endif /* ! BACKSQL_ARBITRARY_KEY */
361 * check for syntax needed here
362 * maybe need binary bind?
364 SQLBindParameter( sth, pno + 2 - po,
366 SQL_C_CHAR, SQL_CHAR,
367 0, 0, at_val->bv_val,
370 Debug( LDAP_DEBUG_TRACE,
371 " backsql_modify_internal(): "
372 "executing \"%s\"\n",
373 at->bam_add_proc, 0, 0 );
374 rc = SQLExecute( sth );
375 if ( rc != SQL_SUCCESS ) {
376 Debug( LDAP_DEBUG_TRACE,
377 " backsql_modify_internal(): "
378 "add_proc execution failed\n",
380 backsql_PrintErrors( bi->db_env,
383 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
384 rs->sr_err = LDAP_OTHER;
385 rs->sr_text = "SQL-backend error";
389 #ifdef BACKSQL_REALLOC_STMT
390 SQLFreeStmt( sth, SQL_DROP );
391 SQLAllocStmt( dbh, &sth );
392 #endif /* BACKSQL_REALLOC_STMT */
396 case LDAP_MOD_DELETE:
397 if ( at->bam_delete_proc == NULL ) {
398 Debug( LDAP_DEBUG_TRACE,
399 " backsql_modify_internal(): "
400 "delete procedure is not defined "
401 "for attribute \"%s\"\n",
402 at->bam_ad->ad_cname.bv_val, 0, 0 );
404 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
405 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
406 rs->sr_text = "operation not permitted "
407 "within namingContext";
414 if ( c_mod->sm_values == NULL ) {
415 Debug( LDAP_DEBUG_TRACE,
416 " backsql_modify_internal(): "
417 "no values given to delete "
418 "for attribute \"%s\" "
419 "-- deleting all values\n",
420 at->bam_ad->ad_cname.bv_val, 0, 0 );
424 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
425 "deleting values for attribute \"%s\"\n",
426 at->bam_ad->ad_cname.bv_val, 0, 0 );
428 for ( i = 0, at_val = c_mod->sm_values;
429 at_val->bv_val != NULL;
431 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
433 SQLBindParameter( sth, 1,
435 SQL_C_ULONG, SQL_INTEGER,
440 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
441 #ifdef BACKSQL_ARBITRARY_KEY
442 SQLBindParameter( sth, pno + 1 + po,
444 SQL_C_CHAR, SQL_VARCHAR,
445 0, 0, e_id->eid_keyval.bv_val, 0, 0 );
446 #else /* ! BACKSQL_ARBITRARY_KEY */
447 SQLBindParameter( sth, pno + 1 + po,
449 SQL_C_ULONG, SQL_INTEGER,
450 0, 0, &e_id->eid_keyval, 0, 0 );
451 #endif /* ! BACKSQL_ARBITRARY_KEY */
454 * check for syntax needed here
455 * maybe need binary bind?
457 SQLBindParameter( sth, pno + 2 - po,
458 SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
459 0, 0, at_val->bv_val,
462 Debug( LDAP_DEBUG_TRACE,
463 " backsql_modify_internal(): "
464 "executing \"%s\"\n",
465 at->bam_delete_proc, 0, 0 );
466 rc = SQLExecDirect( sth, at->bam_delete_proc,
468 if ( rc != SQL_SUCCESS ) {
469 Debug( LDAP_DEBUG_TRACE,
470 " backsql_modify_internal(): "
471 "delete_proc execution "
472 "failed\n", 0, 0, 0 );
473 backsql_PrintErrors( bi->db_env,
476 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
477 rs->sr_err = LDAP_OTHER;
478 rs->sr_text = "SQL-backend error";
482 #ifdef BACKSQL_REALLOC_STMT
483 SQLFreeStmt( sth, SQL_DROP );
484 SQLAllocStmt( dbh, &sth );
485 #endif /* BACKSQL_REALLOC_STMT */
489 #ifndef BACKSQL_REALLOC_STMT
490 SQLFreeStmt( sth, SQL_RESET_PARAMS );
491 #else /* BACKSQL_REALLOC_STMT */
492 SQLFreeStmt( sth, SQL_DROP );
493 #endif /* BACKSQL_REALLOC_STMT */
498 #ifndef BACKSQL_REALLOC_STMT
499 SQLFreeStmt( sth, SQL_DROP );
500 #endif /* BACKSQL_REALLOC_STMT */
502 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
503 rs->sr_err, rs->sr_text ? ": " : "",
504 rs->sr_text ? rs->sr_text : "" );
507 * FIXME: should fail in case one change fails?
513 backsql_add( Operation *op, SlapReply *rs )
515 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
518 unsigned long new_keyval = 0;
521 backsql_oc_map_rec *oc = NULL;
522 backsql_at_map_rec *at_rec = NULL;
523 backsql_entryID parent_id = BACKSQL_ENTRYID_INIT;
526 struct berval *at_val;
528 /* first parameter #, parameter order */
529 SQLUSMALLINT pno, po;
530 /* procedure return code */
532 struct berval realdn = BER_BVNULL,
533 realpdn = BER_BVNULL;
535 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
536 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
539 if ( global_schemacheck ) {
540 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
542 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
544 &rs->sr_text, textbuf, sizeof( textbuf ) );
545 if ( rs->sr_err != LDAP_SUCCESS ) {
546 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
547 "entry failed schema check -- aborting\n",
548 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
553 /* search structural objectClass */
554 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
555 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
560 /* there must exist */
561 assert( at != NULL );
563 /* I guess we should play with sub/supertypes to find a suitable oc */
564 oc = backsql_name2oc( bi, &at->a_vals[0] );
567 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
568 "cannot map structuralObjectClass \"%s\" -- aborting\n",
569 op->oq_add.rs_e->e_name.bv_val,
570 at->a_vals[0].bv_val, 0 );
571 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
572 rs->sr_text = "operation not permitted within namingContext";
576 if ( oc->bom_create_proc == NULL ) {
577 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
578 "create procedure is not defined "
579 "for structuralObjectClass \"%s\" - aborting\n",
580 op->oq_add.rs_e->e_name.bv_val,
581 at->a_vals[0].bv_val, 0 );
582 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
583 rs->sr_text = "operation not permitted within namingContext";
586 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
587 && oc->bom_create_keyval == NULL ) {
588 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
589 "create procedure needs select procedure, "
590 "but none is defined for structuralObjectClass \"%s\" "
592 op->oq_add.rs_e->e_name.bv_val,
593 at->a_vals[0].bv_val, 0 );
594 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
595 rs->sr_text = "operation not permitted within namingContext";
599 rs->sr_err = backsql_get_db_conn( op, &dbh );
600 if ( rs->sr_err != LDAP_SUCCESS ) {
601 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
602 "could not get connection handle - exiting\n",
603 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
604 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
605 ? "SQL-backend error" : NULL;
610 * Check if entry exists
612 realdn = op->oq_add.rs_e->e_name;
613 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
614 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
615 "backsql_api_dn2odbc(\"%s\") failed\n",
616 op->oq_add.rs_e->e_name.bv_val,
617 op->oq_add.rs_e->e_name.bv_val, 0 );
618 rs->sr_err = LDAP_OTHER;
619 rs->sr_text = "SQL-backend error";
623 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
624 if ( rs->sr_err == LDAP_SUCCESS ) {
625 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
627 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
628 rs->sr_err = LDAP_ALREADY_EXISTS;
633 * Get the parent dn and see if the corresponding entry exists.
635 if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
638 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
642 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
643 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
644 "backsql_api_dn2odbc(\"%s\") failed\n",
645 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
646 rs->sr_err = LDAP_OTHER;
647 rs->sr_text = "SQL-backend error";
651 rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
652 if ( rs->sr_err != LDAP_SUCCESS ) {
653 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
654 "could not lookup parent entry for new record \"%s\"\n",
655 op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
657 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
663 * if not attempting to add entry at suffix or with parent ""
665 if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
666 || pdn.bv_len > 0 ) && !is_entry_glue( op->oq_add.rs_e ) )
668 Debug( LDAP_DEBUG_TRACE, " backsql_add: %s denied\n",
669 pdn.bv_len == 0 ? "suffix" : "entry at root",
676 char *matched = NULL;
678 if ( realpdn.bv_val != pdn.bv_val ) {
679 ch_free( realpdn.bv_val );
683 dnParent( &dn, &pdn );
686 * Empty DN ("") defaults to LDAP_SUCCESS
689 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
690 Debug( LDAP_DEBUG_TRACE,
691 " backsql_add(\"%s\"): "
692 "backsql_api_dn2odbc failed\n",
693 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
694 rs->sr_err = LDAP_OTHER;
695 rs->sr_text = "SQL-backend error";
699 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
700 switch ( rs->sr_err ) {
701 case LDAP_NO_SUCH_OBJECT:
702 if ( pdn.bv_len > 0 ) {
705 /* fail over to next case */
708 matched = pdn.bv_val;
709 /* fail over to next case */
712 rs->sr_err = LDAP_NO_SUCH_OBJECT;
713 rs->sr_matched = matched;
719 #ifdef BACKSQL_ARBITRARY_KEY
720 ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
721 #else /* ! BACKSQL_ARBITRARY_KEY */
722 parent_id.eid_id = 0;
723 #endif /* ! BACKSQL_ARBITRARY_KEY */
724 rs->sr_err = LDAP_SUCCESS;
728 /* check "children" pseudo-attribute access to parent */
731 dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
732 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
733 NULL, ACL_WRITE, NULL ) ) {
734 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
739 * create_proc is executed; if expect_return is set, then
740 * an output parameter is bound, which should contain
741 * the id of the added row; otherwise the procedure
742 * is expected to return the id as the first column of a select
745 rc = SQLAllocStmt( dbh, &sth );
746 if ( rc != SQL_SUCCESS ) {
747 rs->sr_err = LDAP_OTHER;
748 rs->sr_text = "SQL-backend error";
752 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
753 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
754 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
757 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n",
758 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
759 rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
760 if ( rc != SQL_SUCCESS ) {
761 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
762 "create_proc execution failed\n",
763 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
764 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
765 SQLFreeStmt( sth, SQL_DROP );
766 rs->sr_err = LDAP_OTHER;
767 rs->sr_text = "SQL-backend error";
771 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
774 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
776 SQLINTEGER value_len;
778 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
779 #ifndef BACKSQL_REALLOC_STMT
780 SQLFreeStmt( sth, SQL_RESET_PARAMS );
781 #else /* BACKSQL_REALLOC_STMT */
782 SQLFreeStmt( sth, SQL_DROP );
783 rc = SQLAllocStmt( dbh, &sth );
784 if ( rc != SQL_SUCCESS ) {
785 rs->sr_err = LDAP_OTHER;
786 rs->sr_text = "SQL-backend error";
789 #endif /* BACKSQL_REALLOC_STMT */
791 rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
792 if ( rc != SQL_SUCCESS ) {
793 rs->sr_err = LDAP_OTHER;
794 rs->sr_text = "SQL-backend error";
800 * the query to know the id of the inserted entry
801 * must be embedded in the create procedure
803 rc = SQLNumResultCols( sth, &ncols );
804 if ( rc != SQL_SUCCESS ) {
805 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
806 "create_proc result evaluation failed\n",
807 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
808 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
809 SQLFreeStmt( sth, SQL_DROP );
810 rs->sr_err = LDAP_OTHER;
811 rs->sr_text = "SQL-backend error";
814 } else if ( ncols != 1 ) {
815 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
816 "create_proc result is bogus (ncols=%d)\n",
817 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
818 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
819 SQLFreeStmt( sth, SQL_DROP );
820 rs->sr_err = LDAP_OTHER;
821 rs->sr_text = "SQL-backend error";
827 SQLCHAR colname[ 64 ];
828 SQLSMALLINT name_len, col_type, col_scale, col_null;
832 * FIXME: check whether col_type is compatible,
833 * if it can be null and so on ...
835 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1,
837 (SQLUINTEGER)( sizeof( colname ) - 1 ),
838 &name_len, &col_type,
839 &col_prec, &col_scale, &col_null );
843 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
844 (SQLPOINTER)&new_keyval,
845 (SQLINTEGER)sizeof( new_keyval ),
848 rc = SQLFetch( sth );
850 if ( value_len <= 0 ) {
851 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
852 "create_proc result is empty?\n",
853 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
854 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
855 SQLFreeStmt( sth, SQL_DROP );
856 rs->sr_err = LDAP_OTHER;
857 rs->sr_text = "SQL-backend error";
862 #ifndef BACKSQL_REALLOC_STMT
863 SQLFreeStmt( sth, SQL_RESET_PARAMS );
864 #else /* BACKSQL_REALLOC_STMT */
865 SQLFreeStmt( sth, SQL_DROP );
866 #endif /* BACKSQL_REALLOC_STMT */
868 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
869 "create_proc returned keyval=%ld\n",
870 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
872 for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
873 SQLUSMALLINT currpos;
875 Debug( LDAP_DEBUG_TRACE, " backsql_add(): "
876 "adding attribute \"%s\"\n",
877 at->a_desc->ad_cname.bv_val, 0, 0 );
881 * - the first occurrence of objectClass, which is used
882 * to determine how to bulid the SQL entry (FIXME ?!?)
883 * - operational attributes
884 * empty attributes (FIXME ?!?)
886 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
890 at_rec = backsql_ad2at( oc, at->a_desc );
892 if ( at_rec == NULL ) {
893 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
894 "attribute \"%s\" is not registered "
895 "in objectclass \"%s\"\n",
896 op->oq_add.rs_e->e_name.bv_val,
897 at->a_desc->ad_cname.bv_val,
898 BACKSQL_OC_NAME( oc ) );
900 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
901 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
902 rs->sr_text = "operation not permitted "
903 "within namingContext";
910 if ( at_rec->bam_add_proc == NULL ) {
911 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
912 "add procedure is not defined "
913 "for attribute \"%s\" "
914 "of structuralObjectClass \"%s\"\n",
915 op->oq_add.rs_e->e_name.bv_val,
916 at->a_desc->ad_cname.bv_val,
917 BACKSQL_OC_NAME( oc ) );
919 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
920 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
921 rs->sr_text = "operation not permitted "
922 "within namingContext";
929 for ( i = 0, at_val = &at->a_vals[ i ];
930 at_val->bv_val != NULL;
931 i++, at_val = &at->a_vals[ i ] )
933 char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
935 #ifdef BACKSQL_REALLOC_STMT
936 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
937 if ( rc != SQL_SUCCESS ) {
939 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
940 rs->sr_err = LDAP_OTHER;
941 rs->sr_text = "SQL-backend error";
947 #endif /* BACKSQL_REALLOC_STMT */
949 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
951 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
952 SQL_C_ULONG, SQL_INTEGER,
958 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
959 currpos = pno + 1 + po;
960 SQLBindParameter( sth, currpos,
961 SQL_PARAM_INPUT, SQL_C_ULONG,
962 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
963 currpos = pno + 2 - po;
966 * Do not deal with the objectClass that is used
969 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
970 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
976 * check for syntax needed here
977 * maybe need binary bind?
980 backsql_BindParamStr( sth, currpos,
981 at_val->bv_val, at_val->bv_len + 1 );
984 snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
986 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
987 "executing \"%s\" %s\n",
988 op->oq_add.rs_e->e_name.bv_val,
989 at_rec->bam_add_proc, logbuf );
991 #ifndef BACKSQL_REALLOC_STMT
992 rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
993 #else /* BACKSQL_REALLOC_STMT */
994 rc = SQLExecute( sth );
995 #endif /* BACKSQL_REALLOC_STMT */
996 if ( rc != SQL_SUCCESS ) {
997 Debug( LDAP_DEBUG_TRACE,
998 " backsql_add(\"%s\"): "
999 "add_proc execution failed\n",
1000 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1001 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1003 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1004 rs->sr_err = LDAP_OTHER;
1005 rs->sr_text = "SQL-backend error";
1009 #ifndef BACKSQL_REALLOC_STMT
1010 SQLFreeStmt( sth, SQL_RESET_PARAMS );
1011 #else /* BACKSQL_REALLOC_STMT */
1012 SQLFreeStmt( sth, SQL_DROP );
1013 #endif /* BACKSQL_REALLOC_STMT */
1019 #ifdef BACKSQL_REALLOC_STMT
1020 rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1021 if ( rc != SQL_SUCCESS ) {
1022 rs->sr_err = LDAP_OTHER;
1023 rs->sr_text = "SQL-backend error";
1026 #endif /* BACKSQL_REALLOC_STMT */
1028 backsql_BindParamStr( sth, 1, realdn.bv_val, BACKSQL_MAX_DN_LEN );
1029 SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1030 0, 0, &oc->bom_id, 0, 0 );
1031 #ifdef BACKSQL_ARBITRARY_KEY
1032 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
1033 0, 0, parent_id.eid_id.bv_val, 0, 0 );
1034 #else /* ! BACKSQL_ARBITRARY_KEY */
1035 SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1036 0, 0, &parent_id.eid_id, 0, 0 );
1037 #endif /* ! BACKSQL_ARBITRARY_KEY */
1038 SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1039 0, 0, &new_keyval, 0, 0 );
1041 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
1042 bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1043 #ifdef BACKSQL_ARBITRARY_KEY
1044 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1045 "parent_id=%s, keyval=%ld\n",
1046 oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1047 #else /* ! BACKSQL_ARBITRARY_KEY */
1048 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
1049 "parent_id=%ld, keyval=%ld\n",
1050 oc->bom_id, parent_id.eid_id, new_keyval );
1051 #endif /* ! BACKSQL_ARBITRARY_KEY */
1052 #ifndef BACKSQL_REALLOC_STMT
1053 rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1054 #else /* BACKSQL_REALLOC_STMT */
1055 rc = SQLExecute( sth );
1056 #endif /* BACKSQL_REALLOC_STMT */
1057 if ( rc != SQL_SUCCESS ) {
1058 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
1059 "could not insert ldap_entries record\n",
1060 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1061 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1064 * execute delete_proc to delete data added !!!
1066 SQLFreeStmt( sth, SQL_DROP );
1067 rs->sr_err = LDAP_OTHER;
1068 rs->sr_text = "SQL-backend error";
1072 SQLFreeStmt( sth, SQL_DROP );
1075 * Commit only if all operations succeed
1077 SQLTransact( SQL_NULL_HENV, dbh,
1078 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1081 * FIXME: NOOP does not work for add -- it works for all
1082 * the other operations, and I don't get the reason :(
1084 * hint: there might be some autocommit in Postgres
1085 * so that when the unique id of the key table is
1086 * automatically increased, there's no rollback.
1087 * We might implement a "rollback" procedure consisting
1088 * in deleting that row.
1092 send_ldap_result( op, rs );
1094 if ( !BER_BVISNULL( &realdn )
1095 && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
1097 ch_free( realdn.bv_val );
1099 if ( !BER_BVISNULL( &realpdn ) && realpdn.bv_val != pdn.bv_val ) {
1100 ch_free( realpdn.bv_val );
1102 if ( !BER_BVISNULL( &parent_id.eid_dn ) ) {
1103 backsql_free_entryID( &parent_id, 0 );
1106 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1107 op->oq_add.rs_e->e_name.bv_val,
1109 rs->sr_text ? rs->sr_text : "" );
1111 return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1114 #endif /* SLAPD_SQL */