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