1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/add.c,v 1.50.2.6 2008/02/11 23:26:48 kurt Exp $ */ 2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2008 The OpenLDAP Foundation. 5 * Portions Copyright 1999 Dmitry Kovalev. 6 * Portions Copyright 2002 Pierangelo Masarati. 7 * Portions Copyright 2004 Mark Adamson. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* ACKNOWLEDGEMENTS: 19 * This work was initially developed by Dmitry Kovalev for inclusion 20 * by OpenLDAP Software. Additional significant contributors include 21 * Pierangelo Masarati and Mark Adamson. 22 23 */ 24 25 #include "portable.h" 26 27 #include <stdio.h> 28 #include <sys/types.h> 29 #include "ac/string.h" 30 31 #include "slap.h" 32 #include "proto-sql.h" 33 34 #ifdef BACKSQL_SYNCPROV 35 #include <lutil.h> 36 #endif /* BACKSQL_SYNCPROV */ 37 38 /* 39 * Skip: 40 * - null values (e.g. delete modification) 41 * - single occurrence of objectClass, because it is already used 42 * to determine how to build the SQL entry 43 * - operational attributes 44 * - empty attributes 45 */ 46 #define backsql_opattr_skip(ad) \ 47 (is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref ) 48 #define backsql_attr_skip(ad, vals) \ 49 ( \ 50 ( (ad) == slap_schema.si_ad_objectClass \ 51 && (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \ 52 || backsql_opattr_skip( (ad) ) \ 53 || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \ 54 ) 55 56 int 57 backsql_modify_delete_all_values( 58 Operation *op, 59 SlapReply *rs, 60 SQLHDBC dbh, 61 backsql_entryID *e_id, 62 backsql_at_map_rec *at ) 63 { 64 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 65 RETCODE rc; 66 SQLHSTMT asth = SQL_NULL_HSTMT; 67 BACKSQL_ROW_NTS row; 68 69 assert( at != NULL ); 70 if ( at->bam_delete_proc == NULL ) { 71 Debug( LDAP_DEBUG_TRACE, 72 " backsql_modify_delete_all_values(): " 73 "missing attribute value delete procedure " 74 "for attr \"%s\"\n", 75 at->bam_ad->ad_cname.bv_val, 0, 0 ); 76 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 77 rs->sr_text = "SQL-backend error"; 78 return rs->sr_err = LDAP_OTHER; 79 } 80 81 return LDAP_SUCCESS; 82 } 83 84 rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 ); 85 if ( rc != SQL_SUCCESS ) { 86 Debug( LDAP_DEBUG_TRACE, 87 " backsql_modify_delete_all_values(): " 88 "error preparing attribute value select query " 89 "\"%s\"\n", 90 at->bam_query, 0, 0 ); 91 backsql_PrintErrors( bi->sql_db_env, dbh, 92 asth, rc ); 93 94 rs->sr_text = "SQL-backend error"; 95 return rs->sr_err = LDAP_OTHER; 96 } 97 98 rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval ); 99 if ( rc != SQL_SUCCESS ) { 100 Debug( LDAP_DEBUG_TRACE, 101 " backsql_modify_delete_all_values(): " 102 "error binding key value parameter " 103 "to attribute value select query\n", 104 0, 0, 0 ); 105 backsql_PrintErrors( bi->sql_db_env, dbh, 106 asth, rc ); 107 SQLFreeStmt( asth, SQL_DROP ); 108 109 rs->sr_text = "SQL-backend error"; 110 return rs->sr_err = LDAP_OTHER; 111 } 112 113 rc = SQLExecute( asth ); 114 if ( !BACKSQL_SUCCESS( rc ) ) { 115 Debug( LDAP_DEBUG_TRACE, 116 " backsql_modify_delete_all_values(): " 117 "error executing attribute value select query\n", 118 0, 0, 0 ); 119 backsql_PrintErrors( bi->sql_db_env, dbh, 120 asth, rc ); 121 SQLFreeStmt( asth, SQL_DROP ); 122 123 rs->sr_text = "SQL-backend error"; 124 return rs->sr_err = LDAP_OTHER; 125 } 126 127 backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx ); 128 for ( rc = SQLFetch( asth ); 129 BACKSQL_SUCCESS( rc ); 130 rc = SQLFetch( asth ) ) 131 { 132 int i; 133 /* first parameter no, parameter order */ 134 SQLUSMALLINT pno = 0, 135 po = 0; 136 /* procedure return code */ 137 int prc = LDAP_SUCCESS; 138 139 for ( i = 0; i < row.ncols; i++ ) { 140 SQLHSTMT sth = SQL_NULL_HSTMT; 141 ber_len_t col_len; 142 143 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 144 if ( rc != SQL_SUCCESS ) { 145 Debug( LDAP_DEBUG_TRACE, 146 " backsql_modify_delete_all_values(): " 147 "error preparing attribute value " 148 "delete procedure " 149 "\"%s\"\n", 150 at->bam_delete_proc, 0, 0 ); 151 backsql_PrintErrors( bi->sql_db_env, dbh, 152 sth, rc ); 153 154 rs->sr_text = "SQL-backend error"; 155 rs->sr_err = LDAP_OTHER; 156 goto done; 157 } 158 159 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 160 pno = 1; 161 rc = backsql_BindParamInt( sth, 1, 162 SQL_PARAM_OUTPUT, &prc ); 163 if ( rc != SQL_SUCCESS ) { 164 Debug( LDAP_DEBUG_TRACE, 165 " backsql_modify_delete_all_values(): " 166 "error binding output parameter for %s[%d]\n", 167 at->bam_ad->ad_cname.bv_val, i, 0 ); 168 backsql_PrintErrors( bi->sql_db_env, dbh, 169 sth, rc ); 170 SQLFreeStmt( sth, SQL_DROP ); 171 172 rs->sr_text = "SQL-backend error"; 173 rs->sr_err = LDAP_OTHER; 174 goto done; 175 } 176 } 177 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 178 rc = backsql_BindParamID( sth, pno + 1 + po, 179 SQL_PARAM_INPUT, &e_id->eid_keyval ); 180 if ( rc != SQL_SUCCESS ) { 181 Debug( LDAP_DEBUG_TRACE, 182 " backsql_modify_delete_all_values(): " 183 "error binding keyval parameter for %s[%d]\n", 184 at->bam_ad->ad_cname.bv_val, i, 0 ); 185 backsql_PrintErrors( bi->sql_db_env, dbh, 186 sth, rc ); 187 SQLFreeStmt( sth, SQL_DROP ); 188 189 rs->sr_text = "SQL-backend error"; 190 rs->sr_err = LDAP_OTHER; 191 goto done; 192 } 193 #ifdef BACKSQL_ARBITRARY_KEY 194 Debug( LDAP_DEBUG_TRACE, 195 " backsql_modify_delete_all_values() " 196 "arg(%d)=%s\n", 197 pno + 1 + po, e_id->eid_keyval.bv_val, 0 ); 198 #else /* ! BACKSQL_ARBITRARY_KEY */ 199 Debug( LDAP_DEBUG_TRACE, 200 " backsql_modify_delete_all_values() " 201 "arg(%d)=%lu\n", 202 pno + 1 + po, e_id->eid_keyval, 0 ); 203 #endif /* ! BACKSQL_ARBITRARY_KEY */ 204 205 /* 206 * check for syntax needed here 207 * maybe need binary bind? 208 */ 209 col_len = strlen( row.cols[ i ] ); 210 rc = backsql_BindParamStr( sth, pno + 2 - po, 211 SQL_PARAM_INPUT, row.cols[ i ], col_len ); 212 if ( rc != SQL_SUCCESS ) { 213 Debug( LDAP_DEBUG_TRACE, 214 " backsql_modify_delete_all_values(): " 215 "error binding value parameter for %s[%d]\n", 216 at->bam_ad->ad_cname.bv_val, i, 0 ); 217 backsql_PrintErrors( bi->sql_db_env, dbh, 218 sth, rc ); 219 SQLFreeStmt( sth, SQL_DROP ); 220 221 rs->sr_text = "SQL-backend error"; 222 rs->sr_err = LDAP_OTHER; 223 goto done; 224 } 225 226 Debug( LDAP_DEBUG_TRACE, 227 " backsql_modify_delete_all_values(): " 228 "arg(%d)=%s; executing \"%s\"\n", 229 pno + 2 - po, row.cols[ i ], 230 at->bam_delete_proc ); 231 rc = SQLExecute( sth ); 232 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 233 rs->sr_err = LDAP_SUCCESS; 234 235 } else { 236 Debug( LDAP_DEBUG_TRACE, 237 " backsql_modify_delete_all_values(): " 238 "delete_proc " 239 "execution failed (rc=%d, prc=%d)\n", 240 rc, prc, 0 ); 241 if ( prc != LDAP_SUCCESS ) { 242 /* SQL procedure executed fine 243 * but returned an error */ 244 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 245 246 } else { 247 backsql_PrintErrors( bi->sql_db_env, dbh, 248 sth, rc ); 249 rs->sr_err = LDAP_OTHER; 250 } 251 rs->sr_text = op->o_req_dn.bv_val; 252 SQLFreeStmt( sth, SQL_DROP ); 253 goto done; 254 } 255 SQLFreeStmt( sth, SQL_DROP ); 256 } 257 } 258 259 rs->sr_err = LDAP_SUCCESS; 260 261 done:; 262 backsql_FreeRow_x( &row, op->o_tmpmemctx ); 263 SQLFreeStmt( asth, SQL_DROP ); 264 265 return rs->sr_err; 266 } 267 268 int 269 backsql_modify_internal( 270 Operation *op, 271 SlapReply *rs, 272 SQLHDBC dbh, 273 backsql_oc_map_rec *oc, 274 backsql_entryID *e_id, 275 Modifications *modlist ) 276 { 277 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 278 RETCODE rc; 279 Modifications *ml; 280 281 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): " 282 "traversing modifications list\n", 0, 0, 0 ); 283 284 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 285 AttributeDescription *ad; 286 int sm_op; 287 static char *sm_ops[] = { "add", "delete", "replace", "increment", NULL }; 288 289 BerVarray sm_values; 290 #if 0 291 /* NOTE: some day we'll have to pass 292 * the normalized values as well */ 293 BerVarray sm_nvalues; 294 #endif 295 backsql_at_map_rec *at = NULL; 296 struct berval *at_val; 297 int i; 298 299 ad = ml->sml_mod.sm_desc; 300 sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP ); 301 sm_values = ml->sml_mod.sm_values; 302 #if 0 303 sm_nvalues = ml->sml_mod.sm_nvalues; 304 #endif 305 306 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 307 "modifying attribute \"%s\" (%s) according to " 308 "mappings for objectClass \"%s\"\n", 309 ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) ); 310 311 if ( backsql_attr_skip( ad, sm_values ) ) { 312 continue; 313 } 314 315 at = backsql_ad2at( oc, ad ); 316 if ( at == NULL ) { 317 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 318 "attribute \"%s\" is not registered " 319 "in objectClass \"%s\"\n", 320 ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 ); 321 322 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 323 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 324 rs->sr_text = "operation not permitted " 325 "within namingContext"; 326 goto done; 327 } 328 329 continue; 330 } 331 332 switch ( sm_op ) { 333 case LDAP_MOD_REPLACE: { 334 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 335 "replacing values for attribute \"%s\"\n", 336 at->bam_ad->ad_cname.bv_val, 0, 0 ); 337 338 if ( at->bam_add_proc == NULL ) { 339 Debug( LDAP_DEBUG_TRACE, 340 " backsql_modify_internal(): " 341 "add procedure is not defined " 342 "for attribute \"%s\" " 343 "- unable to perform replacements\n", 344 at->bam_ad->ad_cname.bv_val, 0, 0 ); 345 346 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 347 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 348 rs->sr_text = "operation not permitted " 349 "within namingContext"; 350 goto done; 351 } 352 353 break; 354 } 355 356 if ( at->bam_delete_proc == NULL ) { 357 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 358 Debug( LDAP_DEBUG_TRACE, 359 " backsql_modify_internal(): " 360 "delete procedure is not defined " 361 "for attribute \"%s\"\n", 362 at->bam_ad->ad_cname.bv_val, 0, 0 ); 363 364 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 365 rs->sr_text = "operation not permitted " 366 "within namingContext"; 367 goto done; 368 } 369 370 Debug( LDAP_DEBUG_TRACE, 371 " backsql_modify_internal(): " 372 "delete procedure is not defined " 373 "for attribute \"%s\" " 374 "- adding only\n", 375 at->bam_ad->ad_cname.bv_val, 0, 0 ); 376 377 goto add_only; 378 } 379 380 del_all: 381 rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at ); 382 if ( rs->sr_err != LDAP_SUCCESS ) { 383 goto done; 384 } 385 386 /* LDAP_MOD_DELETE gets here if all values must be deleted */ 387 if ( sm_op == LDAP_MOD_DELETE ) { 388 break; 389 } 390 } 391 392 /* 393 * PASSTHROUGH - to add new attributes -- do NOT add break 394 */ 395 case LDAP_MOD_ADD: 396 /* case SLAP_MOD_SOFTADD: */ 397 add_only:; 398 if ( at->bam_add_proc == NULL ) { 399 Debug( LDAP_DEBUG_TRACE, 400 " backsql_modify_internal(): " 401 "add procedure is not defined " 402 "for attribute \"%s\"\n", 403 at->bam_ad->ad_cname.bv_val, 0, 0 ); 404 405 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 406 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 407 rs->sr_text = "operation not permitted " 408 "within namingContext"; 409 goto done; 410 } 411 412 break; 413 } 414 415 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 416 "adding new values for attribute \"%s\"\n", 417 at->bam_ad->ad_cname.bv_val, 0, 0 ); 418 419 /* can't add a NULL val array */ 420 assert( sm_values != NULL ); 421 422 for ( i = 0, at_val = sm_values; 423 !BER_BVISNULL( at_val ); 424 i++, at_val++ ) 425 { 426 SQLHSTMT sth = SQL_NULL_HSTMT; 427 /* first parameter position, parameter order */ 428 SQLUSMALLINT pno = 0, 429 po; 430 /* procedure return code */ 431 int prc = LDAP_SUCCESS; 432 433 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 ); 434 if ( rc != SQL_SUCCESS ) { 435 Debug( LDAP_DEBUG_TRACE, 436 " backsql_modify_internal(): " 437 "error preparing add query\n", 438 0, 0, 0 ); 439 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 440 441 rs->sr_err = LDAP_OTHER; 442 rs->sr_text = "SQL-backend error"; 443 goto done; 444 } 445 446 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { 447 pno = 1; 448 rc = backsql_BindParamInt( sth, 1, 449 SQL_PARAM_OUTPUT, &prc ); 450 if ( rc != SQL_SUCCESS ) { 451 Debug( LDAP_DEBUG_TRACE, 452 " backsql_modify_internal(): " 453 "error binding output parameter for %s[%d]\n", 454 at->bam_ad->ad_cname.bv_val, i, 0 ); 455 backsql_PrintErrors( bi->sql_db_env, dbh, 456 sth, rc ); 457 SQLFreeStmt( sth, SQL_DROP ); 458 459 rs->sr_text = "SQL-backend error"; 460 rs->sr_err = LDAP_OTHER; 461 goto done; 462 } 463 } 464 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; 465 rc = backsql_BindParamID( sth, pno + 1 + po, 466 SQL_PARAM_INPUT, &e_id->eid_keyval ); 467 if ( rc != SQL_SUCCESS ) { 468 Debug( LDAP_DEBUG_TRACE, 469 " backsql_modify_internal(): " 470 "error binding keyval parameter for %s[%d]\n", 471 at->bam_ad->ad_cname.bv_val, i, 0 ); 472 backsql_PrintErrors( bi->sql_db_env, dbh, 473 sth, rc ); 474 SQLFreeStmt( sth, SQL_DROP ); 475 476 rs->sr_text = "SQL-backend error"; 477 rs->sr_err = LDAP_OTHER; 478 goto done; 479 } 480 #ifdef BACKSQL_ARBITRARY_KEY 481 Debug( LDAP_DEBUG_TRACE, 482 " backsql_modify_internal(): " 483 "arg(%d)=\"%s\"\n", 484 pno + 1 + po, e_id->eid_keyval.bv_val, 0 ); 485 #else /* ! BACKSQL_ARBITRARY_KEY */ 486 Debug( LDAP_DEBUG_TRACE, 487 " backsql_modify_internal(): " 488 "arg(%d)=\"%lu\"\n", 489 pno + 1 + po, e_id->eid_keyval, 0 ); 490 #endif /* ! BACKSQL_ARBITRARY_KEY */ 491 492 /* 493 * check for syntax needed here 494 * maybe need binary bind? 495 */ 496 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 497 SQL_PARAM_INPUT, at_val ); 498 if ( rc != SQL_SUCCESS ) { 499 Debug( LDAP_DEBUG_TRACE, 500 " backsql_modify_internal(): " 501 "error binding value parameter for %s[%d]\n", 502 at->bam_ad->ad_cname.bv_val, i, 0 ); 503 backsql_PrintErrors( bi->sql_db_env, dbh, 504 sth, rc ); 505 SQLFreeStmt( sth, SQL_DROP ); 506 507 rs->sr_text = "SQL-backend error"; 508 rs->sr_err = LDAP_OTHER; 509 goto done; 510 } 511 Debug( LDAP_DEBUG_TRACE, 512 " backsql_modify_internal(): " 513 "arg(%d)=\"%s\"; executing \"%s\"\n", 514 pno + 2 - po, at_val->bv_val, 515 at->bam_add_proc ); 516 517 rc = SQLExecute( sth ); 518 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 519 rs->sr_err = LDAP_SUCCESS; 520 521 } else { 522 Debug( LDAP_DEBUG_TRACE, 523 " backsql_modify_internal(): " 524 "add_proc execution failed " 525 "(rc=%d, prc=%d)\n", 526 rc, prc, 0 ); 527 if ( prc != LDAP_SUCCESS ) { 528 /* SQL procedure executed fine 529 * but returned an error */ 530 SQLFreeStmt( sth, SQL_DROP ); 531 532 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 533 rs->sr_text = at->bam_ad->ad_cname.bv_val; 534 return rs->sr_err; 535 536 } else { 537 backsql_PrintErrors( bi->sql_db_env, dbh, 538 sth, rc ); 539 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 540 { 541 SQLFreeStmt( sth, SQL_DROP ); 542 543 rs->sr_err = LDAP_OTHER; 544 rs->sr_text = "SQL-backend error"; 545 goto done; 546 } 547 } 548 } 549 SQLFreeStmt( sth, SQL_DROP ); 550 } 551 break; 552 553 case LDAP_MOD_DELETE: 554 if ( at->bam_delete_proc == NULL ) { 555 Debug( LDAP_DEBUG_TRACE, 556 " backsql_modify_internal(): " 557 "delete procedure is not defined " 558 "for attribute \"%s\"\n", 559 at->bam_ad->ad_cname.bv_val, 0, 0 ); 560 561 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 562 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 563 rs->sr_text = "operation not permitted " 564 "within namingContext"; 565 goto done; 566 } 567 568 break; 569 } 570 571 if ( sm_values == NULL ) { 572 Debug( LDAP_DEBUG_TRACE, 573 " backsql_modify_internal(): " 574 "no values given to delete " 575 "for attribute \"%s\" " 576 "-- deleting all values\n", 577 at->bam_ad->ad_cname.bv_val, 0, 0 ); 578 goto del_all; 579 } 580 581 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 582 "deleting values for attribute \"%s\"\n", 583 at->bam_ad->ad_cname.bv_val, 0, 0 ); 584 585 for ( i = 0, at_val = sm_values; 586 !BER_BVISNULL( at_val ); 587 i++, at_val++ ) 588 { 589 SQLHSTMT sth = SQL_NULL_HSTMT; 590 /* first parameter position, parameter order */ 591 SQLUSMALLINT pno = 0, 592 po; 593 /* procedure return code */ 594 int prc = LDAP_SUCCESS; 595 596 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 597 if ( rc != SQL_SUCCESS ) { 598 Debug( LDAP_DEBUG_TRACE, 599 " backsql_modify_internal(): " 600 "error preparing delete query\n", 601 0, 0, 0 ); 602 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 603 604 rs->sr_err = LDAP_OTHER; 605 rs->sr_text = "SQL-backend error"; 606 goto done; 607 } 608 609 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 610 pno = 1; 611 rc = backsql_BindParamInt( sth, 1, 612 SQL_PARAM_OUTPUT, &prc ); 613 if ( rc != SQL_SUCCESS ) { 614 Debug( LDAP_DEBUG_TRACE, 615 " backsql_modify_internal(): " 616 "error binding output parameter for %s[%d]\n", 617 at->bam_ad->ad_cname.bv_val, i, 0 ); 618 backsql_PrintErrors( bi->sql_db_env, dbh, 619 sth, rc ); 620 SQLFreeStmt( sth, SQL_DROP ); 621 622 rs->sr_text = "SQL-backend error"; 623 rs->sr_err = LDAP_OTHER; 624 goto done; 625 } 626 } 627 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 628 rc = backsql_BindParamID( sth, pno + 1 + po, 629 SQL_PARAM_INPUT, &e_id->eid_keyval ); 630 if ( rc != SQL_SUCCESS ) { 631 Debug( LDAP_DEBUG_TRACE, 632 " backsql_modify_internal(): " 633 "error binding keyval parameter for %s[%d]\n", 634 at->bam_ad->ad_cname.bv_val, i, 0 ); 635 backsql_PrintErrors( bi->sql_db_env, dbh, 636 sth, rc ); 637 SQLFreeStmt( sth, SQL_DROP ); 638 639 rs->sr_text = "SQL-backend error"; 640 rs->sr_err = LDAP_OTHER; 641 goto done; 642 } 643 #ifdef BACKSQL_ARBITRARY_KEY 644 Debug( LDAP_DEBUG_TRACE, 645 " backsql_modify_internal(): " 646 "arg(%d)=\"%s\"\n", 647 pno + 1 + po, e_id->eid_keyval.bv_val, 0 ); 648 #else /* ! BACKSQL_ARBITRARY_KEY */ 649 Debug( LDAP_DEBUG_TRACE, 650 " backsql_modify_internal(): " 651 "arg(%d)=\"%lu\"\n", 652 pno + 1 + po, e_id->eid_keyval, 0 ); 653 #endif /* ! BACKSQL_ARBITRARY_KEY */ 654 655 /* 656 * check for syntax needed here 657 * maybe need binary bind? 658 */ 659 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 660 SQL_PARAM_INPUT, at_val ); 661 if ( rc != SQL_SUCCESS ) { 662 Debug( LDAP_DEBUG_TRACE, 663 " backsql_modify_internal(): " 664 "error binding value parameter for %s[%d]\n", 665 at->bam_ad->ad_cname.bv_val, i, 0 ); 666 backsql_PrintErrors( bi->sql_db_env, dbh, 667 sth, rc ); 668 SQLFreeStmt( sth, SQL_DROP ); 669 670 rs->sr_text = "SQL-backend error"; 671 rs->sr_err = LDAP_OTHER; 672 goto done; 673 } 674 675 Debug( LDAP_DEBUG_TRACE, 676 " backsql_modify_internal(): " 677 "executing \"%s\"\n", 678 at->bam_delete_proc, 0, 0 ); 679 rc = SQLExecute( sth ); 680 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) 681 { 682 rs->sr_err = LDAP_SUCCESS; 683 684 } else { 685 Debug( LDAP_DEBUG_TRACE, 686 " backsql_modify_internal(): " 687 "delete_proc execution " 688 "failed (rc=%d, prc=%d)\n", 689 rc, prc, 0 ); 690 691 if ( prc != LDAP_SUCCESS ) { 692 /* SQL procedure executed fine 693 * but returned an error */ 694 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 695 rs->sr_text = at->bam_ad->ad_cname.bv_val; 696 goto done; 697 698 } else { 699 backsql_PrintErrors( bi->sql_db_env, 700 dbh, sth, rc ); 701 SQLFreeStmt( sth, SQL_DROP ); 702 rs->sr_err = LDAP_OTHER; 703 rs->sr_text = at->bam_ad->ad_cname.bv_val; 704 goto done; 705 } 706 } 707 SQLFreeStmt( sth, SQL_DROP ); 708 } 709 break; 710 711 case LDAP_MOD_INCREMENT: 712 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 713 "increment not supported yet\n", 0, 0, 0 ); 714 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 715 rs->sr_err = LDAP_OTHER; 716 rs->sr_text = "SQL-backend error"; 717 goto done; 718 } 719 break; 720 } 721 } 722 723 done:; 724 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n", 725 rs->sr_err, 726 rs->sr_text ? ": " : "", 727 rs->sr_text ? rs->sr_text : "" ); 728 729 /* 730 * FIXME: should fail in case one change fails? 731 */ 732 return rs->sr_err; 733 } 734 735 static int 736 backsql_add_attr( 737 Operation *op, 738 SlapReply *rs, 739 SQLHDBC dbh, 740 backsql_oc_map_rec *oc, 741 Attribute *at, 742 unsigned long new_keyval ) 743 { 744 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 745 backsql_at_map_rec *at_rec = NULL; 746 struct berval *at_val; 747 unsigned long i; 748 RETCODE rc; 749 SQLUSMALLINT currpos; 750 SQLHSTMT sth = SQL_NULL_HSTMT; 751 752 at_rec = backsql_ad2at( oc, at->a_desc ); 753 754 if ( at_rec == NULL ) { 755 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 756 "attribute \"%s\" is not registered " 757 "in objectclass \"%s\"\n", 758 op->ora_e->e_name.bv_val, 759 at->a_desc->ad_cname.bv_val, 760 BACKSQL_OC_NAME( oc ) ); 761 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; 766 } 767 768 return LDAP_SUCCESS; 769 } 770 771 if ( at_rec->bam_add_proc == NULL ) { 772 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 773 "add procedure is not defined " 774 "for attribute \"%s\" " 775 "of structuralObjectClass \"%s\"\n", 776 op->ora_e->e_name.bv_val, 777 at->a_desc->ad_cname.bv_val, 778 BACKSQL_OC_NAME( oc ) ); 779 780 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 781 rs->sr_text = "operation not permitted " 782 "within namingContext"; 783 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 784 } 785 786 return LDAP_SUCCESS; 787 } 788 789 for ( i = 0, at_val = &at->a_vals[ i ]; 790 !BER_BVISNULL( at_val ); 791 i++, at_val = &at->a_vals[ i ] ) 792 { 793 /* procedure return code */ 794 int prc = LDAP_SUCCESS; 795 /* first parameter #, parameter order */ 796 SQLUSMALLINT pno, po; 797 char logbuf[ STRLENOF("val[], id=") + 2*LDAP_PVT_INTTYPE_CHARS(unsigned long)]; 798 799 /* 800 * Do not deal with the objectClass that is used 801 * to build the entry 802 */ 803 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 804 if ( dn_match( at_val, &oc->bom_oc->soc_cname ) ) 805 { 806 continue; 807 } 808 } 809 810 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 ); 811 if ( rc != SQL_SUCCESS ) { 812 rs->sr_text = "SQL-backend error"; 813 return rs->sr_err = LDAP_OTHER; 814 } 815 816 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) { 817 pno = 1; 818 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc ); 819 if ( rc != SQL_SUCCESS ) { 820 Debug( LDAP_DEBUG_TRACE, 821 " backsql_add_attr(): " 822 "error binding output parameter for %s[%lu]\n", 823 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 824 backsql_PrintErrors( bi->sql_db_env, dbh, 825 sth, rc ); 826 SQLFreeStmt( sth, SQL_DROP ); 827 828 rs->sr_text = "SQL-backend error"; 829 return rs->sr_err = LDAP_OTHER; 830 } 831 832 } else { 833 pno = 0; 834 } 835 836 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0; 837 currpos = pno + 1 + po; 838 rc = backsql_BindParamInt( sth, currpos, 839 SQL_PARAM_INPUT, &new_keyval ); 840 if ( rc != SQL_SUCCESS ) { 841 Debug( LDAP_DEBUG_TRACE, 842 " backsql_add_attr(): " 843 "error binding keyval parameter for %s[%lu]\n", 844 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 845 backsql_PrintErrors( bi->sql_db_env, dbh, 846 sth, rc ); 847 SQLFreeStmt( sth, SQL_DROP ); 848 849 rs->sr_text = "SQL-backend error"; 850 return rs->sr_err = LDAP_OTHER; 851 } 852 853 currpos = pno + 2 - po; 854 855 /* 856 * check for syntax needed here 857 * maybe need binary bind? 858 */ 859 860 rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val ); 861 if ( rc != SQL_SUCCESS ) { 862 Debug( LDAP_DEBUG_TRACE, 863 " backsql_add_attr(): " 864 "error binding value parameter for %s[%lu]\n", 865 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 866 backsql_PrintErrors( bi->sql_db_env, dbh, 867 sth, rc ); 868 SQLFreeStmt( sth, SQL_DROP ); 869 870 rs->sr_text = "SQL-backend error"; 871 return rs->sr_err = LDAP_OTHER; 872 } 873 874 #ifdef LDAP_DEBUG 875 snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=%lu", 876 i, new_keyval ); 877 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 878 "executing \"%s\" %s\n", 879 op->ora_e->e_name.bv_val, 880 at_rec->bam_add_proc, logbuf ); 881 #endif 882 rc = SQLExecute( sth ); 883 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 884 rs->sr_err = LDAP_SUCCESS; 885 886 } else { 887 Debug( LDAP_DEBUG_TRACE, 888 " backsql_add_attr(\"%s\"): " 889 "add_proc execution failed (rc=%d, prc=%d)\n", 890 op->ora_e->e_name.bv_val, rc, prc ); 891 if ( prc != LDAP_SUCCESS ) { 892 /* SQL procedure executed fine 893 * but returned an error */ 894 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 895 rs->sr_text = op->ora_e->e_name.bv_val; 896 SQLFreeStmt( sth, SQL_DROP ); 897 return rs->sr_err; 898 899 } else { 900 backsql_PrintErrors( bi->sql_db_env, dbh, 901 sth, rc ); 902 rs->sr_err = LDAP_OTHER; 903 rs->sr_text = op->ora_e->e_name.bv_val; 904 SQLFreeStmt( sth, SQL_DROP ); 905 return rs->sr_err; 906 } 907 } 908 SQLFreeStmt( sth, SQL_DROP ); 909 } 910 911 return LDAP_SUCCESS; 912 } 913 914 int 915 backsql_add( Operation *op, SlapReply *rs ) 916 { 917 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 918 SQLHDBC dbh = SQL_NULL_HDBC; 919 SQLHSTMT sth = SQL_NULL_HSTMT; 920 unsigned long new_keyval = 0; 921 RETCODE rc; 922 backsql_oc_map_rec *oc = NULL; 923 backsql_srch_info bsi = { 0 }; 924 Entry p = { 0 }, *e = NULL; 925 Attribute *at, 926 *at_objectClass = NULL; 927 ObjectClass *soc = NULL; 928 struct berval scname = BER_BVNULL; 929 struct berval pdn; 930 struct berval realdn = BER_BVNULL; 931 int colnum; 932 slap_mask_t mask; 933 934 char textbuf[ SLAP_TEXT_BUFLEN ]; 935 size_t textlen = sizeof( textbuf ); 936 937 #ifdef BACKSQL_SYNCPROV 938 /* 939 * NOTE: fake successful result to force contextCSN to be bumped up 940 */ 941 if ( op->o_sync ) { 942 char buf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; 943 struct berval csn; 944 945 csn.bv_val = buf; 946 csn.bv_len = sizeof( buf ); 947 slap_get_csn( op, &csn, 1 ); 948 949 rs->sr_err = LDAP_SUCCESS; 950 send_ldap_result( op, rs ); 951 952 slap_graduate_commit_csn( op ); 953 954 return 0; 955 } 956 #endif /* BACKSQL_SYNCPROV */ 957 958 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n", 959 op->ora_e->e_name.bv_val, 0, 0 ); 960 961 /* check schema */ 962 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 963 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 964 965 rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, 966 &rs->sr_text, textbuf, sizeof( textbuf ) ); 967 if ( rs->sr_err != LDAP_SUCCESS ) { 968 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 969 "entry failed schema check -- aborting\n", 970 op->ora_e->e_name.bv_val, 0, 0 ); 971 e = NULL; 972 goto done; 973 } 974 } 975 976 slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); 977 978 /* search structuralObjectClass */ 979 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 980 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) { 981 break; 982 } 983 } 984 985 /* there must exist */ 986 if ( at == NULL ) { 987 char buf[ SLAP_TEXT_BUFLEN ]; 988 const char *text; 989 990 /* search structuralObjectClass */ 991 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 992 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 993 break; 994 } 995 } 996 997 if ( at == NULL ) { 998 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 999 "no objectClass\n", 1000 op->ora_e->e_name.bv_val, 0, 0 ); 1001 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 1002 e = NULL; 1003 goto done; 1004 } 1005 1006 rs->sr_err = structural_class( at->a_vals, &soc, NULL, 1007 &text, buf, sizeof( buf ), op->o_tmpmemctx ); 1008 if ( rs->sr_err != LDAP_SUCCESS ) { 1009 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1010 "%s (%d)\n", 1011 op->ora_e->e_name.bv_val, text, rs->sr_err ); 1012 e = NULL; 1013 goto done; 1014 } 1015 scname = soc->soc_cname; 1016 1017 } else { 1018 scname = at->a_vals[0]; 1019 } 1020 1021 /* I guess we should play with sub/supertypes to find a suitable oc */ 1022 oc = backsql_name2oc( bi, &scname ); 1023 1024 if ( oc == NULL ) { 1025 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1026 "cannot map structuralObjectClass \"%s\" -- aborting\n", 1027 op->ora_e->e_name.bv_val, 1028 scname.bv_val, 0 ); 1029 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1030 rs->sr_text = "operation not permitted within namingContext"; 1031 e = NULL; 1032 goto done; 1033 } 1034 1035 if ( oc->bom_create_proc == NULL ) { 1036 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1037 "create procedure is not defined " 1038 "for structuralObjectClass \"%s\" - aborting\n", 1039 op->ora_e->e_name.bv_val, 1040 scname.bv_val, 0 ); 1041 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1042 rs->sr_text = "operation not permitted within namingContext"; 1043 e = NULL; 1044 goto done; 1045 1046 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) 1047 && oc->bom_create_keyval == NULL ) { 1048 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1049 "create procedure needs select procedure, " 1050 "but none is defined for structuralObjectClass \"%s\" " 1051 "- aborting\n", 1052 op->ora_e->e_name.bv_val, 1053 scname.bv_val, 0 ); 1054 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1055 rs->sr_text = "operation not permitted within namingContext"; 1056 e = NULL; 1057 goto done; 1058 } 1059 1060 /* check write access */ 1061 if ( !access_allowed_mask( op, op->ora_e, 1062 slap_schema.si_ad_entry, 1063 NULL, ACL_WADD, NULL, &mask ) ) 1064 { 1065 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1066 e = op->ora_e; 1067 goto done; 1068 } 1069 1070 rs->sr_err = backsql_get_db_conn( op, &dbh ); 1071 if ( rs->sr_err != LDAP_SUCCESS ) { 1072 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1073 "could not get connection handle - exiting\n", 1074 op->ora_e->e_name.bv_val, 0, 0 ); 1075 rs->sr_text = ( rs->sr_err == LDAP_OTHER ) 1076 ? "SQL-backend error" : NULL; 1077 e = NULL; 1078 goto done; 1079 } 1080 1081 /* 1082 * Check if entry exists 1083 * 1084 * NOTE: backsql_api_dn2odbc() is called explicitly because 1085 * we need the mucked DN to pass it to the create procedure. 1086 */ 1087 realdn = op->ora_e->e_name; 1088 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) { 1089 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1090 "backsql_api_dn2odbc(\"%s\") failed\n", 1091 op->ora_e->e_name.bv_val, realdn.bv_val, 0 ); 1092 rs->sr_err = LDAP_OTHER; 1093 rs->sr_text = "SQL-backend error"; 1094 e = NULL; 1095 goto done; 1096 } 1097 1098 rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 ); 1099 if ( rs->sr_err == LDAP_SUCCESS ) { 1100 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1101 "entry exists\n", 1102 op->ora_e->e_name.bv_val, 0, 0 ); 1103 rs->sr_err = LDAP_ALREADY_EXISTS; 1104 e = op->ora_e; 1105 goto done; 1106 } 1107 1108 /* 1109 * Get the parent dn and see if the corresponding entry exists. 1110 */ 1111 if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) { 1112 pdn = slap_empty_bv; 1113 1114 } else { 1115 dnParent( &op->ora_e->e_nname, &pdn ); 1116 1117 /* 1118 * Get the parent 1119 */ 1120 bsi.bsi_e = &p; 1121 rs->sr_err = backsql_init_search( &bsi, &pdn, 1122 LDAP_SCOPE_BASE, 1123 (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, 1124 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 1125 if ( rs->sr_err != LDAP_SUCCESS ) { 1126 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1127 "could not retrieve addDN parent " 1128 "\"%s\" ID - %s matched=\"%s\"\n", 1129 pdn.bv_val, 1130 rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry", 1131 rs->sr_matched ? rs->sr_matched : "(null)" ); 1132 e = &p; 1133 goto done; 1134 } 1135 1136 /* check "children" pseudo-attribute access to parent */ 1137 if ( !access_allowed( op, &p, slap_schema.si_ad_children, 1138 NULL, ACL_WADD, NULL ) ) 1139 { 1140 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1141 e = &p; 1142 goto done; 1143 } 1144 } 1145 1146 /* 1147 * create_proc is executed; if expect_return is set, then 1148 * an output parameter is bound, which should contain 1149 * the id of the added row; otherwise the procedure 1150 * is expected to return the id as the first column of a select 1151 */ 1152 rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 ); 1153 if ( rc != SQL_SUCCESS ) { 1154 rs->sr_err = LDAP_OTHER; 1155 rs->sr_text = "SQL-backend error"; 1156 e = NULL; 1157 goto done; 1158 } 1159 1160 colnum = 1; 1161 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1162 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval ); 1163 if ( rc != SQL_SUCCESS ) { 1164 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1165 "error binding keyval parameter " 1166 "for objectClass %s\n", 1167 op->ora_e->e_name.bv_val, 1168 oc->bom_oc->soc_cname.bv_val, 0 ); 1169 backsql_PrintErrors( bi->sql_db_env, dbh, 1170 sth, rc ); 1171 SQLFreeStmt( sth, SQL_DROP ); 1172 1173 rs->sr_text = "SQL-backend error"; 1174 rs->sr_err = LDAP_OTHER; 1175 e = NULL; 1176 goto done; 1177 } 1178 colnum++; 1179 } 1180 1181 if ( oc->bom_create_hint ) { 1182 at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint ); 1183 if ( at && at->a_vals ) { 1184 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1185 at->a_vals[0].bv_val, 1186 at->a_vals[0].bv_len ); 1187 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1188 "create_proc hint: param = '%s'\n", 1189 at->a_vals[0].bv_val, 0, 0 ); 1190 1191 } else { 1192 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1193 "", 0 ); 1194 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1195 "create_proc hint (%s) not avalable\n", 1196 oc->bom_create_hint->ad_cname.bv_val, 1197 0, 0 ); 1198 } 1199 colnum++; 1200 } 1201 1202 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n", 1203 op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 ); 1204 rc = SQLExecute( sth ); 1205 if ( rc != SQL_SUCCESS ) { 1206 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1207 "create_proc execution failed\n", 1208 op->ora_e->e_name.bv_val, 0, 0 ); 1209 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1210 SQLFreeStmt( sth, SQL_DROP ); 1211 rs->sr_err = LDAP_OTHER; 1212 rs->sr_text = "SQL-backend error"; 1213 e = NULL; 1214 goto done; 1215 } 1216 1217 /* FIXME: after SQLExecute(), the row is already inserted 1218 * (at least with PostgreSQL and unixODBC); needs investigation */ 1219 1220 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1221 SWORD ncols; 1222 SQLINTEGER value_len; 1223 1224 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { 1225 SQLFreeStmt( sth, SQL_DROP ); 1226 1227 rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 ); 1228 if ( rc != SQL_SUCCESS ) { 1229 rs->sr_err = LDAP_OTHER; 1230 rs->sr_text = "SQL-backend error"; 1231 e = NULL; 1232 goto done; 1233 } 1234 1235 rc = SQLExecute( sth ); 1236 if ( rc != SQL_SUCCESS ) { 1237 rs->sr_err = LDAP_OTHER; 1238 rs->sr_text = "SQL-backend error"; 1239 e = NULL; 1240 goto done; 1241 } 1242 } 1243 1244 /* 1245 * the query to know the id of the inserted entry 1246 * must be embedded in the create procedure 1247 */ 1248 rc = SQLNumResultCols( sth, &ncols ); 1249 if ( rc != SQL_SUCCESS ) { 1250 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1251 "create_proc result evaluation failed\n", 1252 op->ora_e->e_name.bv_val, 0, 0 ); 1253 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1254 SQLFreeStmt( sth, SQL_DROP ); 1255 rs->sr_err = LDAP_OTHER; 1256 rs->sr_text = "SQL-backend error"; 1257 e = NULL; 1258 goto done; 1259 1260 } else if ( ncols != 1 ) { 1261 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1262 "create_proc result is bogus (ncols=%d)\n", 1263 op->ora_e->e_name.bv_val, ncols, 0 ); 1264 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1265 SQLFreeStmt( sth, SQL_DROP ); 1266 rs->sr_err = LDAP_OTHER; 1267 rs->sr_text = "SQL-backend error"; 1268 e = NULL; 1269 goto done; 1270 } 1271 1272 #if 0 1273 { 1274 SQLCHAR colname[ 64 ]; 1275 SQLSMALLINT name_len, col_type, col_scale, col_null; 1276 UDWORD col_prec; 1277 1278 /* 1279 * FIXME: check whether col_type is compatible, 1280 * if it can be null and so on ... 1281 */ 1282 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 1283 &colname[ 0 ], 1284 (SQLUINTEGER)( sizeof( colname ) - 1 ), 1285 &name_len, &col_type, 1286 &col_prec, &col_scale, &col_null ); 1287 } 1288 #endif 1289 1290 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG, 1291 (SQLPOINTER)&new_keyval, 1292 (SQLINTEGER)sizeof( new_keyval ), 1293 &value_len ); 1294 1295 rc = SQLFetch( sth ); 1296 1297 if ( value_len <= 0 ) { 1298 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1299 "create_proc result is empty?\n", 1300 op->ora_e->e_name.bv_val, 0, 0 ); 1301 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1302 SQLFreeStmt( sth, SQL_DROP ); 1303 rs->sr_err = LDAP_OTHER; 1304 rs->sr_text = "SQL-backend error"; 1305 e = NULL; 1306 goto done; 1307 } 1308 } 1309 1310 SQLFreeStmt( sth, SQL_DROP ); 1311 1312 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1313 "create_proc returned keyval=%ld\n", 1314 op->ora_e->e_name.bv_val, new_keyval, 0 ); 1315 1316 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 ); 1317 if ( rc != SQL_SUCCESS ) { 1318 rs->sr_err = LDAP_OTHER; 1319 rs->sr_text = "SQL-backend error"; 1320 e = NULL; 1321 goto done; 1322 } 1323 1324 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn ); 1325 if ( rc != SQL_SUCCESS ) { 1326 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1327 "error binding DN parameter for objectClass %s\n", 1328 op->ora_e->e_name.bv_val, 1329 oc->bom_oc->soc_cname.bv_val, 0 ); 1330 backsql_PrintErrors( bi->sql_db_env, dbh, 1331 sth, rc ); 1332 SQLFreeStmt( sth, SQL_DROP ); 1333 1334 rs->sr_text = "SQL-backend error"; 1335 rs->sr_err = LDAP_OTHER; 1336 e = NULL; 1337 goto done; 1338 } 1339 1340 rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id ); 1341 if ( rc != SQL_SUCCESS ) { 1342 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1343 "error binding objectClass ID parameter " 1344 "for objectClass %s\n", 1345 op->ora_e->e_name.bv_val, 1346 oc->bom_oc->soc_cname.bv_val, 0 ); 1347 backsql_PrintErrors( bi->sql_db_env, dbh, 1348 sth, rc ); 1349 SQLFreeStmt( sth, SQL_DROP ); 1350 1351 rs->sr_text = "SQL-backend error"; 1352 rs->sr_err = LDAP_OTHER; 1353 e = NULL; 1354 goto done; 1355 } 1356 1357 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id ); 1358 if ( rc != SQL_SUCCESS ) { 1359 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1360 "error binding parent ID parameter " 1361 "for objectClass %s\n", 1362 op->ora_e->e_name.bv_val, 1363 oc->bom_oc->soc_cname.bv_val, 0 ); 1364 backsql_PrintErrors( bi->sql_db_env, dbh, 1365 sth, rc ); 1366 SQLFreeStmt( sth, SQL_DROP ); 1367 1368 rs->sr_text = "SQL-backend error"; 1369 rs->sr_err = LDAP_OTHER; 1370 e = NULL; 1371 goto done; 1372 } 1373 1374 rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval ); 1375 if ( rc != SQL_SUCCESS ) { 1376 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1377 "error binding entry ID parameter " 1378 "for objectClass %s\n", 1379 op->ora_e->e_name.bv_val, 1380 oc->bom_oc->soc_cname.bv_val, 0 ); 1381 backsql_PrintErrors( bi->sql_db_env, dbh, 1382 sth, rc ); 1383 SQLFreeStmt( sth, SQL_DROP ); 1384 1385 rs->sr_text = "SQL-backend error"; 1386 rs->sr_err = LDAP_OTHER; 1387 e = NULL; 1388 goto done; 1389 } 1390 1391 Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n", 1392 bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 0 ); 1393 #ifdef BACKSQL_ARBITRARY_KEY 1394 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, " 1395 "p_id=%s, keyval=%ld\n", 1396 oc->bom_id, bsi.bsi_base_id.eid_id.bv_val, new_keyval ); 1397 #else /* ! BACKSQL_ARBITRARY_KEY */ 1398 Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, " 1399 "p_id=%ld, keyval=%ld\n", 1400 oc->bom_id, bsi.bsi_base_id.eid_id, new_keyval ); 1401 #endif /* ! BACKSQL_ARBITRARY_KEY */ 1402 rc = SQLExecute( sth ); 1403 if ( rc != SQL_SUCCESS ) { 1404 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1405 "could not insert ldap_entries record\n", 1406 op->ora_e->e_name.bv_val, 0, 0 ); 1407 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 1408 1409 /* 1410 * execute delete_proc to delete data added !!! 1411 */ 1412 SQLFreeStmt( sth, SQL_DROP ); 1413 rs->sr_err = LDAP_OTHER; 1414 rs->sr_text = "SQL-backend error"; 1415 e = NULL; 1416 goto done; 1417 } 1418 1419 SQLFreeStmt( sth, SQL_DROP ); 1420 1421 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 1422 Debug( LDAP_DEBUG_TRACE, " backsql_add(): " 1423 "adding attribute \"%s\"\n", 1424 at->a_desc->ad_cname.bv_val, 0, 0 ); 1425 1426 /* 1427 * Skip: 1428 * - the first occurrence of objectClass, which is used 1429 * to determine how to build the SQL entry (FIXME ?!?) 1430 * - operational attributes 1431 * - empty attributes (FIXME ?!?) 1432 */ 1433 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) { 1434 continue; 1435 } 1436 1437 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 1438 at_objectClass = at; 1439 continue; 1440 } 1441 1442 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval ); 1443 if ( rs->sr_err != LDAP_SUCCESS ) { 1444 e = op->ora_e; 1445 goto done; 1446 } 1447 } 1448 1449 if ( at_objectClass ) { 1450 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, 1451 at_objectClass, new_keyval ); 1452 if ( rs->sr_err != LDAP_SUCCESS ) { 1453 e = op->ora_e; 1454 goto done; 1455 } 1456 } 1457 1458 done:; 1459 /* 1460 * Commit only if all operations succeed 1461 */ 1462 if ( sth != SQL_NULL_HSTMT ) { 1463 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 1464 1465 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 1466 assert( e == NULL ); 1467 CompletionType = SQL_COMMIT; 1468 } 1469 1470 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 1471 } 1472 1473 /* 1474 * FIXME: NOOP does not work for add -- it works for all 1475 * the other operations, and I don't get the reason :( 1476 * 1477 * hint: there might be some autocommit in Postgres 1478 * so that when the unique id of the key table is 1479 * automatically increased, there's no rollback. 1480 * We might implement a "rollback" procedure consisting 1481 * in deleting that row. 1482 */ 1483 1484 if ( e != NULL ) { 1485 int disclose = 1; 1486 1487 if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 1488 /* mask already collected */ 1489 disclose = 0; 1490 1491 } else if ( e == &p && !access_allowed( op, &p, 1492 slap_schema.si_ad_entry, NULL, 1493 ACL_DISCLOSE, NULL ) ) 1494 { 1495 disclose = 0; 1496 } 1497 1498 if ( disclose == 0 ) { 1499 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1500 rs->sr_text = NULL; 1501 rs->sr_matched = NULL; 1502 if ( rs->sr_ref ) { 1503 ber_bvarray_free( rs->sr_ref ); 1504 rs->sr_ref = NULL; 1505 } 1506 } 1507 } 1508 1509 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 1510 rs->sr_err = LDAP_X_NO_OPERATION; 1511 } 1512 1513 send_ldap_result( op, rs ); 1514 slap_graduate_commit_csn( op ); 1515 1516 if ( !BER_BVISNULL( &realdn ) 1517 && realdn.bv_val != op->ora_e->e_name.bv_val ) 1518 { 1519 ch_free( realdn.bv_val ); 1520 } 1521 1522 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 1523 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 1524 } 1525 1526 if ( !BER_BVISNULL( &p.e_nname ) ) { 1527 backsql_entry_clean( op, &p ); 1528 } 1529 1530 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n", 1531 op->ora_e->e_name.bv_val, 1532 rs->sr_err, 1533 rs->sr_text ? rs->sr_text : "" ); 1534 1535 rs->sr_text = NULL; 1536 rs->sr_matched = NULL; 1537 if ( rs->sr_ref ) { 1538 ber_bvarray_free( rs->sr_ref ); 1539 rs->sr_ref = NULL; 1540 } 1541 1542 return rs->sr_err; 1543 } 1544 1545