1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 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 56int 57backsql_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 194 Debug( LDAP_DEBUG_TRACE, 195 " backsql_modify_delete_all_values() " 196 "arg(%d)=" BACKSQL_IDFMT "\n", 197 pno + 1 + po, 198 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 199 200 /* 201 * check for syntax needed here 202 * maybe need binary bind? 203 */ 204 col_len = strlen( row.cols[ i ] ); 205 rc = backsql_BindParamStr( sth, pno + 2 - po, 206 SQL_PARAM_INPUT, row.cols[ i ], col_len ); 207 if ( rc != SQL_SUCCESS ) { 208 Debug( LDAP_DEBUG_TRACE, 209 " backsql_modify_delete_all_values(): " 210 "error binding value parameter for %s[%d]\n", 211 at->bam_ad->ad_cname.bv_val, i, 0 ); 212 backsql_PrintErrors( bi->sql_db_env, dbh, 213 sth, rc ); 214 SQLFreeStmt( sth, SQL_DROP ); 215 216 rs->sr_text = "SQL-backend error"; 217 rs->sr_err = LDAP_OTHER; 218 goto done; 219 } 220 221 Debug( LDAP_DEBUG_TRACE, 222 " backsql_modify_delete_all_values(): " 223 "arg(%d)=%s; executing \"%s\"\n", 224 pno + 2 - po, row.cols[ i ], 225 at->bam_delete_proc ); 226 rc = SQLExecute( sth ); 227 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 228 rs->sr_err = LDAP_SUCCESS; 229 230 } else { 231 Debug( LDAP_DEBUG_TRACE, 232 " backsql_modify_delete_all_values(): " 233 "delete_proc " 234 "execution failed (rc=%d, prc=%d)\n", 235 rc, prc, 0 ); 236 if ( prc != LDAP_SUCCESS ) { 237 /* SQL procedure executed fine 238 * but returned an error */ 239 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 240 241 } else { 242 backsql_PrintErrors( bi->sql_db_env, dbh, 243 sth, rc ); 244 rs->sr_err = LDAP_OTHER; 245 } 246 rs->sr_text = op->o_req_dn.bv_val; 247 SQLFreeStmt( sth, SQL_DROP ); 248 goto done; 249 } 250 SQLFreeStmt( sth, SQL_DROP ); 251 } 252 } 253 254 rs->sr_err = LDAP_SUCCESS; 255 256done:; 257 backsql_FreeRow_x( &row, op->o_tmpmemctx ); 258 SQLFreeStmt( asth, SQL_DROP ); 259 260 return rs->sr_err; 261} 262 263int 264backsql_modify_internal( 265 Operation *op, 266 SlapReply *rs, 267 SQLHDBC dbh, 268 backsql_oc_map_rec *oc, 269 backsql_entryID *e_id, 270 Modifications *modlist ) 271{ 272 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 273 RETCODE rc; 274 Modifications *ml; 275 276 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): " 277 "traversing modifications list\n", 0, 0, 0 ); 278 279 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 280 AttributeDescription *ad; 281 int sm_op; 282 static char *sm_ops[] = { "add", "delete", "replace", "increment", NULL }; 283 284 BerVarray sm_values; 285#if 0 286 /* NOTE: some day we'll have to pass 287 * the normalized values as well */ 288 BerVarray sm_nvalues; 289#endif 290 backsql_at_map_rec *at = NULL; 291 struct berval *at_val; 292 int i; 293 294 ad = ml->sml_mod.sm_desc; 295 sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP ); 296 sm_values = ml->sml_mod.sm_values; 297#if 0 298 sm_nvalues = ml->sml_mod.sm_nvalues; 299#endif 300 301 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 302 "modifying attribute \"%s\" (%s) according to " 303 "mappings for objectClass \"%s\"\n", 304 ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) ); 305 306 if ( backsql_attr_skip( ad, sm_values ) ) { 307 continue; 308 } 309 310 at = backsql_ad2at( oc, ad ); 311 if ( at == NULL ) { 312 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 313 "attribute \"%s\" is not registered " 314 "in objectClass \"%s\"\n", 315 ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 ); 316 317 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 318 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 319 rs->sr_text = "operation not permitted " 320 "within namingContext"; 321 goto done; 322 } 323 324 continue; 325 } 326 327 switch ( sm_op ) { 328 case LDAP_MOD_REPLACE: { 329 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 330 "replacing values for attribute \"%s\"\n", 331 at->bam_ad->ad_cname.bv_val, 0, 0 ); 332 333 if ( at->bam_add_proc == NULL ) { 334 Debug( LDAP_DEBUG_TRACE, 335 " backsql_modify_internal(): " 336 "add procedure is not defined " 337 "for attribute \"%s\" " 338 "- unable to perform replacements\n", 339 at->bam_ad->ad_cname.bv_val, 0, 0 ); 340 341 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 342 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 343 rs->sr_text = "operation not permitted " 344 "within namingContext"; 345 goto done; 346 } 347 348 break; 349 } 350 351 if ( at->bam_delete_proc == NULL ) { 352 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 353 Debug( LDAP_DEBUG_TRACE, 354 " backsql_modify_internal(): " 355 "delete procedure is not defined " 356 "for attribute \"%s\"\n", 357 at->bam_ad->ad_cname.bv_val, 0, 0 ); 358 359 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 360 rs->sr_text = "operation not permitted " 361 "within namingContext"; 362 goto done; 363 } 364 365 Debug( LDAP_DEBUG_TRACE, 366 " backsql_modify_internal(): " 367 "delete procedure is not defined " 368 "for attribute \"%s\" " 369 "- adding only\n", 370 at->bam_ad->ad_cname.bv_val, 0, 0 ); 371 372 goto add_only; 373 } 374 375del_all: 376 rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at ); 377 if ( rs->sr_err != LDAP_SUCCESS ) { 378 goto done; 379 } 380 381 /* LDAP_MOD_DELETE gets here if all values must be deleted */ 382 if ( sm_op == LDAP_MOD_DELETE ) { 383 break; 384 } 385 } 386 387 /* 388 * PASSTHROUGH - to add new attributes -- do NOT add break 389 */ 390 case LDAP_MOD_ADD: 391 /* case SLAP_MOD_SOFTADD: */ 392 /* case SLAP_MOD_ADD_IF_NOT_PRESENT: */ 393add_only:; 394 if ( at->bam_add_proc == NULL ) { 395 Debug( LDAP_DEBUG_TRACE, 396 " backsql_modify_internal(): " 397 "add procedure is not defined " 398 "for attribute \"%s\"\n", 399 at->bam_ad->ad_cname.bv_val, 0, 0 ); 400 401 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 402 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 403 rs->sr_text = "operation not permitted " 404 "within namingContext"; 405 goto done; 406 } 407 408 break; 409 } 410 411 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 412 "adding new values for attribute \"%s\"\n", 413 at->bam_ad->ad_cname.bv_val, 0, 0 ); 414 415 /* can't add a NULL val array */ 416 assert( sm_values != NULL ); 417 418 for ( i = 0, at_val = sm_values; 419 !BER_BVISNULL( at_val ); 420 i++, at_val++ ) 421 { 422 SQLHSTMT sth = SQL_NULL_HSTMT; 423 /* first parameter position, parameter order */ 424 SQLUSMALLINT pno = 0, 425 po; 426 /* procedure return code */ 427 int prc = LDAP_SUCCESS; 428 429 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 ); 430 if ( rc != SQL_SUCCESS ) { 431 Debug( LDAP_DEBUG_TRACE, 432 " backsql_modify_internal(): " 433 "error preparing add query\n", 434 0, 0, 0 ); 435 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 436 437 rs->sr_err = LDAP_OTHER; 438 rs->sr_text = "SQL-backend error"; 439 goto done; 440 } 441 442 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { 443 pno = 1; 444 rc = backsql_BindParamInt( sth, 1, 445 SQL_PARAM_OUTPUT, &prc ); 446 if ( rc != SQL_SUCCESS ) { 447 Debug( LDAP_DEBUG_TRACE, 448 " backsql_modify_internal(): " 449 "error binding output parameter for %s[%d]\n", 450 at->bam_ad->ad_cname.bv_val, i, 0 ); 451 backsql_PrintErrors( bi->sql_db_env, dbh, 452 sth, rc ); 453 SQLFreeStmt( sth, SQL_DROP ); 454 455 rs->sr_text = "SQL-backend error"; 456 rs->sr_err = LDAP_OTHER; 457 goto done; 458 } 459 } 460 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; 461 rc = backsql_BindParamID( sth, pno + 1 + po, 462 SQL_PARAM_INPUT, &e_id->eid_keyval ); 463 if ( rc != SQL_SUCCESS ) { 464 Debug( LDAP_DEBUG_TRACE, 465 " backsql_modify_internal(): " 466 "error binding keyval parameter for %s[%d]\n", 467 at->bam_ad->ad_cname.bv_val, i, 0 ); 468 backsql_PrintErrors( bi->sql_db_env, dbh, 469 sth, rc ); 470 SQLFreeStmt( sth, SQL_DROP ); 471 472 rs->sr_text = "SQL-backend error"; 473 rs->sr_err = LDAP_OTHER; 474 goto done; 475 } 476 477 Debug( LDAP_DEBUG_TRACE, 478 " backsql_modify_internal(): " 479 "arg(%d)=" BACKSQL_IDFMT "\n", 480 pno + 1 + po, 481 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 482 483 /* 484 * check for syntax needed here 485 * maybe need binary bind? 486 */ 487 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 488 SQL_PARAM_INPUT, at_val ); 489 if ( rc != SQL_SUCCESS ) { 490 Debug( LDAP_DEBUG_TRACE, 491 " backsql_modify_internal(): " 492 "error binding value parameter for %s[%d]\n", 493 at->bam_ad->ad_cname.bv_val, i, 0 ); 494 backsql_PrintErrors( bi->sql_db_env, dbh, 495 sth, rc ); 496 SQLFreeStmt( sth, SQL_DROP ); 497 498 rs->sr_text = "SQL-backend error"; 499 rs->sr_err = LDAP_OTHER; 500 goto done; 501 } 502 Debug( LDAP_DEBUG_TRACE, 503 " backsql_modify_internal(): " 504 "arg(%d)=\"%s\"; executing \"%s\"\n", 505 pno + 2 - po, at_val->bv_val, 506 at->bam_add_proc ); 507 508 rc = SQLExecute( sth ); 509 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 510 rs->sr_err = LDAP_SUCCESS; 511 512 } else { 513 Debug( LDAP_DEBUG_TRACE, 514 " backsql_modify_internal(): " 515 "add_proc execution failed " 516 "(rc=%d, prc=%d)\n", 517 rc, prc, 0 ); 518 if ( prc != LDAP_SUCCESS ) { 519 /* SQL procedure executed fine 520 * but returned an error */ 521 SQLFreeStmt( sth, SQL_DROP ); 522 523 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 524 rs->sr_text = at->bam_ad->ad_cname.bv_val; 525 return rs->sr_err; 526 527 } else { 528 backsql_PrintErrors( bi->sql_db_env, dbh, 529 sth, rc ); 530 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 531 { 532 SQLFreeStmt( sth, SQL_DROP ); 533 534 rs->sr_err = LDAP_OTHER; 535 rs->sr_text = "SQL-backend error"; 536 goto done; 537 } 538 } 539 } 540 SQLFreeStmt( sth, SQL_DROP ); 541 } 542 break; 543 544 case LDAP_MOD_DELETE: 545 /* case SLAP_MOD_SOFTDEL: */ 546 if ( at->bam_delete_proc == NULL ) { 547 Debug( LDAP_DEBUG_TRACE, 548 " backsql_modify_internal(): " 549 "delete procedure is not defined " 550 "for attribute \"%s\"\n", 551 at->bam_ad->ad_cname.bv_val, 0, 0 ); 552 553 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 554 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 555 rs->sr_text = "operation not permitted " 556 "within namingContext"; 557 goto done; 558 } 559 560 break; 561 } 562 563 if ( sm_values == NULL ) { 564 Debug( LDAP_DEBUG_TRACE, 565 " backsql_modify_internal(): " 566 "no values given to delete " 567 "for attribute \"%s\" " 568 "-- deleting all values\n", 569 at->bam_ad->ad_cname.bv_val, 0, 0 ); 570 goto del_all; 571 } 572 573 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 574 "deleting values for attribute \"%s\"\n", 575 at->bam_ad->ad_cname.bv_val, 0, 0 ); 576 577 for ( i = 0, at_val = sm_values; 578 !BER_BVISNULL( at_val ); 579 i++, at_val++ ) 580 { 581 SQLHSTMT sth = SQL_NULL_HSTMT; 582 /* first parameter position, parameter order */ 583 SQLUSMALLINT pno = 0, 584 po; 585 /* procedure return code */ 586 int prc = LDAP_SUCCESS; 587 588 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 589 if ( rc != SQL_SUCCESS ) { 590 Debug( LDAP_DEBUG_TRACE, 591 " backsql_modify_internal(): " 592 "error preparing delete query\n", 593 0, 0, 0 ); 594 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 595 596 rs->sr_err = LDAP_OTHER; 597 rs->sr_text = "SQL-backend error"; 598 goto done; 599 } 600 601 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 602 pno = 1; 603 rc = backsql_BindParamInt( sth, 1, 604 SQL_PARAM_OUTPUT, &prc ); 605 if ( rc != SQL_SUCCESS ) { 606 Debug( LDAP_DEBUG_TRACE, 607 " backsql_modify_internal(): " 608 "error binding output parameter for %s[%d]\n", 609 at->bam_ad->ad_cname.bv_val, i, 0 ); 610 backsql_PrintErrors( bi->sql_db_env, dbh, 611 sth, rc ); 612 SQLFreeStmt( sth, SQL_DROP ); 613 614 rs->sr_text = "SQL-backend error"; 615 rs->sr_err = LDAP_OTHER; 616 goto done; 617 } 618 } 619 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 620 rc = backsql_BindParamID( sth, pno + 1 + po, 621 SQL_PARAM_INPUT, &e_id->eid_keyval ); 622 if ( rc != SQL_SUCCESS ) { 623 Debug( LDAP_DEBUG_TRACE, 624 " backsql_modify_internal(): " 625 "error binding keyval parameter for %s[%d]\n", 626 at->bam_ad->ad_cname.bv_val, i, 0 ); 627 backsql_PrintErrors( bi->sql_db_env, dbh, 628 sth, rc ); 629 SQLFreeStmt( sth, SQL_DROP ); 630 631 rs->sr_text = "SQL-backend error"; 632 rs->sr_err = LDAP_OTHER; 633 goto done; 634 } 635 636 Debug( LDAP_DEBUG_TRACE, 637 " backsql_modify_internal(): " 638 "arg(%d)=" BACKSQL_IDFMT "\n", 639 pno + 1 + po, 640 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 641 642 /* 643 * check for syntax needed here 644 * maybe need binary bind? 645 */ 646 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 647 SQL_PARAM_INPUT, at_val ); 648 if ( rc != SQL_SUCCESS ) { 649 Debug( LDAP_DEBUG_TRACE, 650 " backsql_modify_internal(): " 651 "error binding value parameter for %s[%d]\n", 652 at->bam_ad->ad_cname.bv_val, i, 0 ); 653 backsql_PrintErrors( bi->sql_db_env, dbh, 654 sth, rc ); 655 SQLFreeStmt( sth, SQL_DROP ); 656 657 rs->sr_text = "SQL-backend error"; 658 rs->sr_err = LDAP_OTHER; 659 goto done; 660 } 661 662 Debug( LDAP_DEBUG_TRACE, 663 " backsql_modify_internal(): " 664 "executing \"%s\"\n", 665 at->bam_delete_proc, 0, 0 ); 666 rc = SQLExecute( sth ); 667 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) 668 { 669 rs->sr_err = LDAP_SUCCESS; 670 671 } else { 672 Debug( LDAP_DEBUG_TRACE, 673 " backsql_modify_internal(): " 674 "delete_proc execution " 675 "failed (rc=%d, prc=%d)\n", 676 rc, prc, 0 ); 677 678 if ( prc != LDAP_SUCCESS ) { 679 /* SQL procedure executed fine 680 * but returned an error */ 681 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 682 rs->sr_text = at->bam_ad->ad_cname.bv_val; 683 goto done; 684 685 } else { 686 backsql_PrintErrors( bi->sql_db_env, 687 dbh, sth, rc ); 688 SQLFreeStmt( sth, SQL_DROP ); 689 rs->sr_err = LDAP_OTHER; 690 rs->sr_text = at->bam_ad->ad_cname.bv_val; 691 goto done; 692 } 693 } 694 SQLFreeStmt( sth, SQL_DROP ); 695 } 696 break; 697 698 case LDAP_MOD_INCREMENT: 699 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 700 "increment not supported yet\n", 0, 0, 0 ); 701 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 702 rs->sr_err = LDAP_OTHER; 703 rs->sr_text = "SQL-backend error"; 704 goto done; 705 } 706 break; 707 } 708 } 709 710done:; 711 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n", 712 rs->sr_err, 713 rs->sr_text ? ": " : "", 714 rs->sr_text ? rs->sr_text : "" ); 715 716 /* 717 * FIXME: should fail in case one change fails? 718 */ 719 return rs->sr_err; 720} 721 722static int 723backsql_add_attr( 724 Operation *op, 725 SlapReply *rs, 726 SQLHDBC dbh, 727 backsql_oc_map_rec *oc, 728 Attribute *at, 729 backsql_key_t new_keyval ) 730{ 731 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 732 backsql_at_map_rec *at_rec = NULL; 733 struct berval *at_val; 734 unsigned long i; 735 RETCODE rc; 736 SQLUSMALLINT currpos; 737 SQLHSTMT sth = SQL_NULL_HSTMT; 738 739 at_rec = backsql_ad2at( oc, at->a_desc ); 740 741 if ( at_rec == NULL ) { 742 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 743 "attribute \"%s\" is not registered " 744 "in objectclass \"%s\"\n", 745 op->ora_e->e_name.bv_val, 746 at->a_desc->ad_cname.bv_val, 747 BACKSQL_OC_NAME( oc ) ); 748 749 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 750 rs->sr_text = "operation not permitted " 751 "within namingContext"; 752 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 753 } 754 755 return LDAP_SUCCESS; 756 } 757 758 if ( at_rec->bam_add_proc == NULL ) { 759 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 760 "add procedure is not defined " 761 "for attribute \"%s\" " 762 "of structuralObjectClass \"%s\"\n", 763 op->ora_e->e_name.bv_val, 764 at->a_desc->ad_cname.bv_val, 765 BACKSQL_OC_NAME( oc ) ); 766 767 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 768 rs->sr_text = "operation not permitted " 769 "within namingContext"; 770 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 771 } 772 773 return LDAP_SUCCESS; 774 } 775 776 for ( i = 0, at_val = &at->a_vals[ i ]; 777 !BER_BVISNULL( at_val ); 778 i++, at_val = &at->a_vals[ i ] ) 779 { 780 /* procedure return code */ 781 int prc = LDAP_SUCCESS; 782 /* first parameter #, parameter order */ 783 SQLUSMALLINT pno, po; 784 char logbuf[ STRLENOF("val[], id=") + 2*LDAP_PVT_INTTYPE_CHARS(unsigned long)]; 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, 0 ); 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, 0 ); 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, 0 ); 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 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 863 snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=" BACKSQL_IDNUMFMT, 864 i, new_keyval ); 865 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 866 "executing \"%s\" %s\n", 867 op->ora_e->e_name.bv_val, 868 at_rec->bam_add_proc, logbuf ); 869 } 870#endif 871 rc = SQLExecute( sth ); 872 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 873 rs->sr_err = LDAP_SUCCESS; 874 875 } else { 876 Debug( LDAP_DEBUG_TRACE, 877 " backsql_add_attr(\"%s\"): " 878 "add_proc execution failed (rc=%d, prc=%d)\n", 879 op->ora_e->e_name.bv_val, rc, prc ); 880 if ( prc != LDAP_SUCCESS ) { 881 /* SQL procedure executed fine 882 * but returned an error */ 883 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 884 rs->sr_text = op->ora_e->e_name.bv_val; 885 SQLFreeStmt( sth, SQL_DROP ); 886 return rs->sr_err; 887 888 } else { 889 backsql_PrintErrors( bi->sql_db_env, dbh, 890 sth, rc ); 891 rs->sr_err = LDAP_OTHER; 892 rs->sr_text = op->ora_e->e_name.bv_val; 893 SQLFreeStmt( sth, SQL_DROP ); 894 return rs->sr_err; 895 } 896 } 897 SQLFreeStmt( sth, SQL_DROP ); 898 } 899 900 return LDAP_SUCCESS; 901} 902 903int 904backsql_add( Operation *op, SlapReply *rs ) 905{ 906 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 907 SQLHDBC dbh = SQL_NULL_HDBC; 908 SQLHSTMT sth = SQL_NULL_HSTMT; 909 backsql_key_t new_keyval = 0; 910 RETCODE rc; 911 backsql_oc_map_rec *oc = NULL; 912 backsql_srch_info bsi = { 0 }; 913 Entry p = { 0 }, *e = NULL; 914 Attribute *at, 915 *at_objectClass = NULL; 916 ObjectClass *soc = NULL; 917 struct berval scname = BER_BVNULL; 918 struct berval pdn; 919 struct berval realdn = BER_BVNULL; 920 int colnum; 921 slap_mask_t mask; 922 923 char textbuf[ SLAP_TEXT_BUFLEN ]; 924 size_t textlen = sizeof( textbuf ); 925 926#ifdef BACKSQL_SYNCPROV 927 /* 928 * NOTE: fake successful result to force contextCSN to be bumped up 929 */ 930 if ( op->o_sync ) { 931 char buf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 932 struct berval csn; 933 934 csn.bv_val = buf; 935 csn.bv_len = sizeof( buf ); 936 slap_get_csn( op, &csn, 1 ); 937 938 rs->sr_err = LDAP_SUCCESS; 939 send_ldap_result( op, rs ); 940 941 slap_graduate_commit_csn( op ); 942 943 return 0; 944 } 945#endif /* BACKSQL_SYNCPROV */ 946 947 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n", 948 op->ora_e->e_name.bv_val, 0, 0 ); 949 950 /* check schema */ 951 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 952 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 953 954 rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, NULL, 955 &rs->sr_text, textbuf, sizeof( textbuf ) ); 956 if ( rs->sr_err != LDAP_SUCCESS ) { 957 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 958 "entry failed schema check -- aborting\n", 959 op->ora_e->e_name.bv_val, 0, 0 ); 960 e = NULL; 961 goto done; 962 } 963 } 964 965 slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); 966 967 if ( get_assert( op ) && 968 ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 969 { 970 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 971 "assertion control failed -- aborting\n", 972 op->ora_e->e_name.bv_val, 0, 0 ); 973 e = NULL; 974 rs->sr_err = LDAP_ASSERTION_FAILED; 975 goto done; 976 } 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_BindParamNumID( 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 SQLLEN 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=" BACKSQL_IDNUMFMT "\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_BindParamNumID( 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_BindParamNumID( 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 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1392 char buf[ SLAP_TEXT_BUFLEN ]; 1393 1394 snprintf( buf, sizeof(buf), 1395 "executing \"%s\" for dn=\"%s\" oc_map_id=" BACKSQL_IDNUMFMT " p_id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDNUMFMT, 1396 bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 1397 oc->bom_id, BACKSQL_IDARG(bsi.bsi_base_id.eid_id), 1398 new_keyval ); 1399 Debug( LDAP_DEBUG_TRACE, " backsql_add(): %s\n", buf, 0, 0 ); 1400 } 1401 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 1458done:; 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