1 /* $NetBSD: add.c,v 1.2 2020/08/11 13:15:42 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2020 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.2 2020/08/11 13:15:42 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, 0, 0 ); 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, 0, 0 ); 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 0, 0, 0 ); 110 backsql_PrintErrors( bi->sql_db_env, dbh, 111 asth, rc ); 112 SQLFreeStmt( asth, SQL_DROP ); 113 114 rs->sr_text = "SQL-backend error"; 115 return rs->sr_err = LDAP_OTHER; 116 } 117 118 rc = SQLExecute( asth ); 119 if ( !BACKSQL_SUCCESS( rc ) ) { 120 Debug( LDAP_DEBUG_TRACE, 121 " backsql_modify_delete_all_values(): " 122 "error executing attribute value select query\n", 123 0, 0, 0 ); 124 backsql_PrintErrors( bi->sql_db_env, dbh, 125 asth, rc ); 126 SQLFreeStmt( asth, SQL_DROP ); 127 128 rs->sr_text = "SQL-backend error"; 129 return rs->sr_err = LDAP_OTHER; 130 } 131 132 backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx ); 133 for ( rc = SQLFetch( asth ); 134 BACKSQL_SUCCESS( rc ); 135 rc = SQLFetch( asth ) ) 136 { 137 int i; 138 /* first parameter no, parameter order */ 139 SQLUSMALLINT pno = 0, 140 po = 0; 141 /* procedure return code */ 142 int prc = LDAP_SUCCESS; 143 144 for ( i = 0; i < row.ncols; i++ ) { 145 SQLHSTMT sth = SQL_NULL_HSTMT; 146 ber_len_t col_len; 147 148 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 149 if ( rc != SQL_SUCCESS ) { 150 Debug( LDAP_DEBUG_TRACE, 151 " backsql_modify_delete_all_values(): " 152 "error preparing attribute value " 153 "delete procedure " 154 "\"%s\"\n", 155 at->bam_delete_proc, 0, 0 ); 156 backsql_PrintErrors( bi->sql_db_env, dbh, 157 sth, rc ); 158 159 rs->sr_text = "SQL-backend error"; 160 rs->sr_err = LDAP_OTHER; 161 goto done; 162 } 163 164 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 165 pno = 1; 166 rc = backsql_BindParamInt( sth, 1, 167 SQL_PARAM_OUTPUT, &prc ); 168 if ( rc != SQL_SUCCESS ) { 169 Debug( LDAP_DEBUG_TRACE, 170 " backsql_modify_delete_all_values(): " 171 "error binding output parameter for %s[%d]\n", 172 at->bam_ad->ad_cname.bv_val, i, 0 ); 173 backsql_PrintErrors( bi->sql_db_env, dbh, 174 sth, rc ); 175 SQLFreeStmt( sth, SQL_DROP ); 176 177 rs->sr_text = "SQL-backend error"; 178 rs->sr_err = LDAP_OTHER; 179 goto done; 180 } 181 } 182 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 183 rc = backsql_BindParamID( sth, pno + 1 + po, 184 SQL_PARAM_INPUT, &e_id->eid_keyval ); 185 if ( rc != SQL_SUCCESS ) { 186 Debug( LDAP_DEBUG_TRACE, 187 " backsql_modify_delete_all_values(): " 188 "error binding keyval parameter for %s[%d]\n", 189 at->bam_ad->ad_cname.bv_val, i, 0 ); 190 backsql_PrintErrors( bi->sql_db_env, dbh, 191 sth, rc ); 192 SQLFreeStmt( sth, SQL_DROP ); 193 194 rs->sr_text = "SQL-backend error"; 195 rs->sr_err = LDAP_OTHER; 196 goto done; 197 } 198 199 Debug( LDAP_DEBUG_TRACE, 200 " backsql_modify_delete_all_values() " 201 "arg(%d)=" BACKSQL_IDFMT "\n", 202 pno + 1 + po, 203 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 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 /* case SLAP_MOD_ADD_IF_NOT_PRESENT: */ 398 add_only:; 399 if ( at->bam_add_proc == NULL ) { 400 Debug( LDAP_DEBUG_TRACE, 401 " backsql_modify_internal(): " 402 "add procedure is not defined " 403 "for attribute \"%s\"\n", 404 at->bam_ad->ad_cname.bv_val, 0, 0 ); 405 406 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 407 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 408 rs->sr_text = "operation not permitted " 409 "within namingContext"; 410 goto done; 411 } 412 413 break; 414 } 415 416 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 417 "adding new values for attribute \"%s\"\n", 418 at->bam_ad->ad_cname.bv_val, 0, 0 ); 419 420 /* can't add a NULL val array */ 421 assert( sm_values != NULL ); 422 423 for ( i = 0, at_val = sm_values; 424 !BER_BVISNULL( at_val ); 425 i++, at_val++ ) 426 { 427 SQLHSTMT sth = SQL_NULL_HSTMT; 428 /* first parameter position, parameter order */ 429 SQLUSMALLINT pno = 0, 430 po; 431 /* procedure return code */ 432 int prc = LDAP_SUCCESS; 433 434 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 ); 435 if ( rc != SQL_SUCCESS ) { 436 Debug( LDAP_DEBUG_TRACE, 437 " backsql_modify_internal(): " 438 "error preparing add query\n", 439 0, 0, 0 ); 440 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 441 442 rs->sr_err = LDAP_OTHER; 443 rs->sr_text = "SQL-backend error"; 444 goto done; 445 } 446 447 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { 448 pno = 1; 449 rc = backsql_BindParamInt( sth, 1, 450 SQL_PARAM_OUTPUT, &prc ); 451 if ( rc != SQL_SUCCESS ) { 452 Debug( LDAP_DEBUG_TRACE, 453 " backsql_modify_internal(): " 454 "error binding output parameter for %s[%d]\n", 455 at->bam_ad->ad_cname.bv_val, i, 0 ); 456 backsql_PrintErrors( bi->sql_db_env, dbh, 457 sth, rc ); 458 SQLFreeStmt( sth, SQL_DROP ); 459 460 rs->sr_text = "SQL-backend error"; 461 rs->sr_err = LDAP_OTHER; 462 goto done; 463 } 464 } 465 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; 466 rc = backsql_BindParamID( sth, pno + 1 + po, 467 SQL_PARAM_INPUT, &e_id->eid_keyval ); 468 if ( rc != SQL_SUCCESS ) { 469 Debug( LDAP_DEBUG_TRACE, 470 " backsql_modify_internal(): " 471 "error binding keyval parameter for %s[%d]\n", 472 at->bam_ad->ad_cname.bv_val, i, 0 ); 473 backsql_PrintErrors( bi->sql_db_env, dbh, 474 sth, rc ); 475 SQLFreeStmt( sth, SQL_DROP ); 476 477 rs->sr_text = "SQL-backend error"; 478 rs->sr_err = LDAP_OTHER; 479 goto done; 480 } 481 482 Debug( LDAP_DEBUG_TRACE, 483 " backsql_modify_internal(): " 484 "arg(%d)=" BACKSQL_IDFMT "\n", 485 pno + 1 + po, 486 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 487 488 /* 489 * check for syntax needed here 490 * maybe need binary bind? 491 */ 492 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 493 SQL_PARAM_INPUT, at_val ); 494 if ( rc != SQL_SUCCESS ) { 495 Debug( LDAP_DEBUG_TRACE, 496 " backsql_modify_internal(): " 497 "error binding value parameter for %s[%d]\n", 498 at->bam_ad->ad_cname.bv_val, i, 0 ); 499 backsql_PrintErrors( bi->sql_db_env, dbh, 500 sth, rc ); 501 SQLFreeStmt( sth, SQL_DROP ); 502 503 rs->sr_text = "SQL-backend error"; 504 rs->sr_err = LDAP_OTHER; 505 goto done; 506 } 507 Debug( LDAP_DEBUG_TRACE, 508 " backsql_modify_internal(): " 509 "arg(%d)=\"%s\"; executing \"%s\"\n", 510 pno + 2 - po, at_val->bv_val, 511 at->bam_add_proc ); 512 513 rc = SQLExecute( sth ); 514 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 515 rs->sr_err = LDAP_SUCCESS; 516 517 } else { 518 Debug( LDAP_DEBUG_TRACE, 519 " backsql_modify_internal(): " 520 "add_proc execution failed " 521 "(rc=%d, prc=%d)\n", 522 rc, prc, 0 ); 523 if ( prc != LDAP_SUCCESS ) { 524 /* SQL procedure executed fine 525 * but returned an error */ 526 SQLFreeStmt( sth, SQL_DROP ); 527 528 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 529 rs->sr_text = at->bam_ad->ad_cname.bv_val; 530 return rs->sr_err; 531 532 } else { 533 backsql_PrintErrors( bi->sql_db_env, dbh, 534 sth, rc ); 535 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 536 { 537 SQLFreeStmt( sth, SQL_DROP ); 538 539 rs->sr_err = LDAP_OTHER; 540 rs->sr_text = "SQL-backend error"; 541 goto done; 542 } 543 } 544 } 545 SQLFreeStmt( sth, SQL_DROP ); 546 } 547 break; 548 549 case LDAP_MOD_DELETE: 550 /* case SLAP_MOD_SOFTDEL: */ 551 if ( at->bam_delete_proc == NULL ) { 552 Debug( LDAP_DEBUG_TRACE, 553 " backsql_modify_internal(): " 554 "delete procedure is not defined " 555 "for attribute \"%s\"\n", 556 at->bam_ad->ad_cname.bv_val, 0, 0 ); 557 558 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 559 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 560 rs->sr_text = "operation not permitted " 561 "within namingContext"; 562 goto done; 563 } 564 565 break; 566 } 567 568 if ( sm_values == NULL ) { 569 Debug( LDAP_DEBUG_TRACE, 570 " backsql_modify_internal(): " 571 "no values given to delete " 572 "for attribute \"%s\" " 573 "-- deleting all values\n", 574 at->bam_ad->ad_cname.bv_val, 0, 0 ); 575 goto del_all; 576 } 577 578 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 579 "deleting values for attribute \"%s\"\n", 580 at->bam_ad->ad_cname.bv_val, 0, 0 ); 581 582 for ( i = 0, at_val = sm_values; 583 !BER_BVISNULL( at_val ); 584 i++, at_val++ ) 585 { 586 SQLHSTMT sth = SQL_NULL_HSTMT; 587 /* first parameter position, parameter order */ 588 SQLUSMALLINT pno = 0, 589 po; 590 /* procedure return code */ 591 int prc = LDAP_SUCCESS; 592 593 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 594 if ( rc != SQL_SUCCESS ) { 595 Debug( LDAP_DEBUG_TRACE, 596 " backsql_modify_internal(): " 597 "error preparing delete query\n", 598 0, 0, 0 ); 599 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 600 601 rs->sr_err = LDAP_OTHER; 602 rs->sr_text = "SQL-backend error"; 603 goto done; 604 } 605 606 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 607 pno = 1; 608 rc = backsql_BindParamInt( sth, 1, 609 SQL_PARAM_OUTPUT, &prc ); 610 if ( rc != SQL_SUCCESS ) { 611 Debug( LDAP_DEBUG_TRACE, 612 " backsql_modify_internal(): " 613 "error binding output parameter for %s[%d]\n", 614 at->bam_ad->ad_cname.bv_val, i, 0 ); 615 backsql_PrintErrors( bi->sql_db_env, dbh, 616 sth, rc ); 617 SQLFreeStmt( sth, SQL_DROP ); 618 619 rs->sr_text = "SQL-backend error"; 620 rs->sr_err = LDAP_OTHER; 621 goto done; 622 } 623 } 624 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 625 rc = backsql_BindParamID( sth, pno + 1 + po, 626 SQL_PARAM_INPUT, &e_id->eid_keyval ); 627 if ( rc != SQL_SUCCESS ) { 628 Debug( LDAP_DEBUG_TRACE, 629 " backsql_modify_internal(): " 630 "error binding keyval parameter for %s[%d]\n", 631 at->bam_ad->ad_cname.bv_val, i, 0 ); 632 backsql_PrintErrors( bi->sql_db_env, dbh, 633 sth, rc ); 634 SQLFreeStmt( sth, SQL_DROP ); 635 636 rs->sr_text = "SQL-backend error"; 637 rs->sr_err = LDAP_OTHER; 638 goto done; 639 } 640 641 Debug( LDAP_DEBUG_TRACE, 642 " backsql_modify_internal(): " 643 "arg(%d)=" BACKSQL_IDFMT "\n", 644 pno + 1 + po, 645 BACKSQL_IDARG(e_id->eid_keyval), 0 ); 646 647 /* 648 * check for syntax needed here 649 * maybe need binary bind? 650 */ 651 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 652 SQL_PARAM_INPUT, at_val ); 653 if ( rc != SQL_SUCCESS ) { 654 Debug( LDAP_DEBUG_TRACE, 655 " backsql_modify_internal(): " 656 "error binding value parameter for %s[%d]\n", 657 at->bam_ad->ad_cname.bv_val, i, 0 ); 658 backsql_PrintErrors( bi->sql_db_env, dbh, 659 sth, rc ); 660 SQLFreeStmt( sth, SQL_DROP ); 661 662 rs->sr_text = "SQL-backend error"; 663 rs->sr_err = LDAP_OTHER; 664 goto done; 665 } 666 667 Debug( LDAP_DEBUG_TRACE, 668 " backsql_modify_internal(): " 669 "executing \"%s\"\n", 670 at->bam_delete_proc, 0, 0 ); 671 rc = SQLExecute( sth ); 672 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) 673 { 674 rs->sr_err = LDAP_SUCCESS; 675 676 } else { 677 Debug( LDAP_DEBUG_TRACE, 678 " backsql_modify_internal(): " 679 "delete_proc execution " 680 "failed (rc=%d, prc=%d)\n", 681 rc, prc, 0 ); 682 683 if ( prc != LDAP_SUCCESS ) { 684 /* SQL procedure executed fine 685 * but returned an error */ 686 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 687 rs->sr_text = at->bam_ad->ad_cname.bv_val; 688 goto done; 689 690 } else { 691 backsql_PrintErrors( bi->sql_db_env, 692 dbh, sth, rc ); 693 SQLFreeStmt( sth, SQL_DROP ); 694 rs->sr_err = LDAP_OTHER; 695 rs->sr_text = at->bam_ad->ad_cname.bv_val; 696 goto done; 697 } 698 } 699 SQLFreeStmt( sth, SQL_DROP ); 700 } 701 break; 702 703 case LDAP_MOD_INCREMENT: 704 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 705 "increment not supported yet\n", 0, 0, 0 ); 706 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 707 rs->sr_err = LDAP_OTHER; 708 rs->sr_text = "SQL-backend error"; 709 goto done; 710 } 711 break; 712 } 713 } 714 715 done:; 716 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n", 717 rs->sr_err, 718 rs->sr_text ? ": " : "", 719 rs->sr_text ? rs->sr_text : "" ); 720 721 /* 722 * FIXME: should fail in case one change fails? 723 */ 724 return rs->sr_err; 725 } 726 727 static int 728 backsql_add_attr( 729 Operation *op, 730 SlapReply *rs, 731 SQLHDBC dbh, 732 backsql_oc_map_rec *oc, 733 Attribute *at, 734 backsql_key_t new_keyval ) 735 { 736 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 737 backsql_at_map_rec *at_rec = NULL; 738 struct berval *at_val; 739 unsigned long i; 740 RETCODE rc; 741 SQLUSMALLINT currpos; 742 SQLHSTMT sth = SQL_NULL_HSTMT; 743 744 at_rec = backsql_ad2at( oc, at->a_desc ); 745 746 if ( at_rec == NULL ) { 747 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 748 "attribute \"%s\" is not registered " 749 "in objectclass \"%s\"\n", 750 op->ora_e->e_name.bv_val, 751 at->a_desc->ad_cname.bv_val, 752 BACKSQL_OC_NAME( oc ) ); 753 754 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 755 rs->sr_text = "operation not permitted " 756 "within namingContext"; 757 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 758 } 759 760 return LDAP_SUCCESS; 761 } 762 763 if ( at_rec->bam_add_proc == NULL ) { 764 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 765 "add procedure is not defined " 766 "for attribute \"%s\" " 767 "of structuralObjectClass \"%s\"\n", 768 op->ora_e->e_name.bv_val, 769 at->a_desc->ad_cname.bv_val, 770 BACKSQL_OC_NAME( oc ) ); 771 772 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 773 rs->sr_text = "operation not permitted " 774 "within namingContext"; 775 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 776 } 777 778 return LDAP_SUCCESS; 779 } 780 781 for ( i = 0, at_val = &at->a_vals[ i ]; 782 !BER_BVISNULL( at_val ); 783 i++, at_val = &at->a_vals[ i ] ) 784 { 785 /* procedure return code */ 786 int prc = LDAP_SUCCESS; 787 /* first parameter #, parameter order */ 788 SQLUSMALLINT pno, po; 789 char logbuf[ STRLENOF("val[], id=") + 2*LDAP_PVT_INTTYPE_CHARS(unsigned long)]; 790 791 /* 792 * Do not deal with the objectClass that is used 793 * to build the entry 794 */ 795 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 796 if ( dn_match( at_val, &oc->bom_oc->soc_cname ) ) 797 { 798 continue; 799 } 800 } 801 802 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 ); 803 if ( rc != SQL_SUCCESS ) { 804 rs->sr_text = "SQL-backend error"; 805 return rs->sr_err = LDAP_OTHER; 806 } 807 808 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) { 809 pno = 1; 810 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc ); 811 if ( rc != SQL_SUCCESS ) { 812 Debug( LDAP_DEBUG_TRACE, 813 " backsql_add_attr(): " 814 "error binding output parameter for %s[%lu]\n", 815 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 816 backsql_PrintErrors( bi->sql_db_env, dbh, 817 sth, rc ); 818 SQLFreeStmt( sth, SQL_DROP ); 819 820 rs->sr_text = "SQL-backend error"; 821 return rs->sr_err = LDAP_OTHER; 822 } 823 824 } else { 825 pno = 0; 826 } 827 828 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0; 829 currpos = pno + 1 + po; 830 rc = backsql_BindParamNumID( sth, currpos, 831 SQL_PARAM_INPUT, &new_keyval ); 832 if ( rc != SQL_SUCCESS ) { 833 Debug( LDAP_DEBUG_TRACE, 834 " backsql_add_attr(): " 835 "error binding keyval parameter for %s[%lu]\n", 836 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 837 backsql_PrintErrors( bi->sql_db_env, dbh, 838 sth, rc ); 839 SQLFreeStmt( sth, SQL_DROP ); 840 841 rs->sr_text = "SQL-backend error"; 842 return rs->sr_err = LDAP_OTHER; 843 } 844 845 currpos = pno + 2 - po; 846 847 /* 848 * check for syntax needed here 849 * maybe need binary bind? 850 */ 851 852 rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val ); 853 if ( rc != SQL_SUCCESS ) { 854 Debug( LDAP_DEBUG_TRACE, 855 " backsql_add_attr(): " 856 "error binding value parameter for %s[%lu]\n", 857 at_rec->bam_ad->ad_cname.bv_val, i, 0 ); 858 backsql_PrintErrors( bi->sql_db_env, dbh, 859 sth, rc ); 860 SQLFreeStmt( sth, SQL_DROP ); 861 862 rs->sr_text = "SQL-backend error"; 863 return rs->sr_err = LDAP_OTHER; 864 } 865 866 #ifdef LDAP_DEBUG 867 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 868 snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=" BACKSQL_IDNUMFMT, 869 i, new_keyval ); 870 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 871 "executing \"%s\" %s\n", 872 op->ora_e->e_name.bv_val, 873 at_rec->bam_add_proc, logbuf ); 874 } 875 #endif 876 rc = SQLExecute( sth ); 877 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 878 rs->sr_err = LDAP_SUCCESS; 879 880 } else { 881 Debug( LDAP_DEBUG_TRACE, 882 " backsql_add_attr(\"%s\"): " 883 "add_proc execution failed (rc=%d, prc=%d)\n", 884 op->ora_e->e_name.bv_val, rc, prc ); 885 if ( prc != LDAP_SUCCESS ) { 886 /* SQL procedure executed fine 887 * but returned an error */ 888 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 889 rs->sr_text = op->ora_e->e_name.bv_val; 890 SQLFreeStmt( sth, SQL_DROP ); 891 return rs->sr_err; 892 893 } else { 894 backsql_PrintErrors( bi->sql_db_env, dbh, 895 sth, rc ); 896 rs->sr_err = LDAP_OTHER; 897 rs->sr_text = op->ora_e->e_name.bv_val; 898 SQLFreeStmt( sth, SQL_DROP ); 899 return rs->sr_err; 900 } 901 } 902 SQLFreeStmt( sth, SQL_DROP ); 903 } 904 905 return LDAP_SUCCESS; 906 } 907 908 int 909 backsql_add( Operation *op, SlapReply *rs ) 910 { 911 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 912 SQLHDBC dbh = SQL_NULL_HDBC; 913 SQLHSTMT sth = SQL_NULL_HSTMT; 914 backsql_key_t new_keyval = 0; 915 RETCODE rc; 916 backsql_oc_map_rec *oc = NULL; 917 backsql_srch_info bsi = { 0 }; 918 Entry p = { 0 }, *e = NULL; 919 Attribute *at, 920 *at_objectClass = NULL; 921 ObjectClass *soc = NULL; 922 struct berval scname = BER_BVNULL; 923 struct berval pdn; 924 struct berval realdn = BER_BVNULL; 925 int colnum; 926 slap_mask_t mask; 927 928 char textbuf[ SLAP_TEXT_BUFLEN ]; 929 size_t textlen = sizeof( textbuf ); 930 931 #ifdef BACKSQL_SYNCPROV 932 /* 933 * NOTE: fake successful result to force contextCSN to be bumped up 934 */ 935 if ( op->o_sync ) { 936 char buf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 937 struct berval csn; 938 939 csn.bv_val = buf; 940 csn.bv_len = sizeof( buf ); 941 slap_get_csn( op, &csn, 1 ); 942 943 rs->sr_err = LDAP_SUCCESS; 944 send_ldap_result( op, rs ); 945 946 slap_graduate_commit_csn( op ); 947 948 return 0; 949 } 950 #endif /* BACKSQL_SYNCPROV */ 951 952 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n", 953 op->ora_e->e_name.bv_val, 0, 0 ); 954 955 /* check schema */ 956 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 957 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 958 959 rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, NULL, 960 &rs->sr_text, textbuf, sizeof( textbuf ) ); 961 if ( rs->sr_err != LDAP_SUCCESS ) { 962 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 963 "entry failed schema check -- aborting\n", 964 op->ora_e->e_name.bv_val, 0, 0 ); 965 e = NULL; 966 goto done; 967 } 968 } 969 970 slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); 971 972 if ( get_assert( op ) && 973 ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 974 { 975 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 976 "assertion control failed -- aborting\n", 977 op->ora_e->e_name.bv_val, 0, 0 ); 978 e = NULL; 979 rs->sr_err = LDAP_ASSERTION_FAILED; 980 goto done; 981 } 982 983 /* search structuralObjectClass */ 984 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 985 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) { 986 break; 987 } 988 } 989 990 /* there must exist */ 991 if ( at == NULL ) { 992 char buf[ SLAP_TEXT_BUFLEN ]; 993 const char *text; 994 995 /* search structuralObjectClass */ 996 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 997 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 998 break; 999 } 1000 } 1001 1002 if ( at == NULL ) { 1003 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1004 "no objectClass\n", 1005 op->ora_e->e_name.bv_val, 0, 0 ); 1006 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 1007 e = NULL; 1008 goto done; 1009 } 1010 1011 rs->sr_err = structural_class( at->a_vals, &soc, NULL, 1012 &text, buf, sizeof( buf ), op->o_tmpmemctx ); 1013 if ( rs->sr_err != LDAP_SUCCESS ) { 1014 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1015 "%s (%d)\n", 1016 op->ora_e->e_name.bv_val, text, rs->sr_err ); 1017 e = NULL; 1018 goto done; 1019 } 1020 scname = soc->soc_cname; 1021 1022 } else { 1023 scname = at->a_vals[0]; 1024 } 1025 1026 /* I guess we should play with sub/supertypes to find a suitable oc */ 1027 oc = backsql_name2oc( bi, &scname ); 1028 1029 if ( oc == NULL ) { 1030 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1031 "cannot map structuralObjectClass \"%s\" -- aborting\n", 1032 op->ora_e->e_name.bv_val, 1033 scname.bv_val, 0 ); 1034 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1035 rs->sr_text = "operation not permitted within namingContext"; 1036 e = NULL; 1037 goto done; 1038 } 1039 1040 if ( oc->bom_create_proc == NULL ) { 1041 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1042 "create procedure is not defined " 1043 "for structuralObjectClass \"%s\" - aborting\n", 1044 op->ora_e->e_name.bv_val, 1045 scname.bv_val, 0 ); 1046 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1047 rs->sr_text = "operation not permitted within namingContext"; 1048 e = NULL; 1049 goto done; 1050 1051 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) 1052 && oc->bom_create_keyval == NULL ) { 1053 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1054 "create procedure needs select procedure, " 1055 "but none is defined for structuralObjectClass \"%s\" " 1056 "- aborting\n", 1057 op->ora_e->e_name.bv_val, 1058 scname.bv_val, 0 ); 1059 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1060 rs->sr_text = "operation not permitted within namingContext"; 1061 e = NULL; 1062 goto done; 1063 } 1064 1065 /* check write access */ 1066 if ( !access_allowed_mask( op, op->ora_e, 1067 slap_schema.si_ad_entry, 1068 NULL, ACL_WADD, NULL, &mask ) ) 1069 { 1070 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1071 e = op->ora_e; 1072 goto done; 1073 } 1074 1075 rs->sr_err = backsql_get_db_conn( op, &dbh ); 1076 if ( rs->sr_err != LDAP_SUCCESS ) { 1077 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1078 "could not get connection handle - exiting\n", 1079 op->ora_e->e_name.bv_val, 0, 0 ); 1080 rs->sr_text = ( rs->sr_err == LDAP_OTHER ) 1081 ? "SQL-backend error" : NULL; 1082 e = NULL; 1083 goto done; 1084 } 1085 1086 /* 1087 * Check if entry exists 1088 * 1089 * NOTE: backsql_api_dn2odbc() is called explicitly because 1090 * we need the mucked DN to pass it to the create procedure. 1091 */ 1092 realdn = op->ora_e->e_name; 1093 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) { 1094 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1095 "backsql_api_dn2odbc(\"%s\") failed\n", 1096 op->ora_e->e_name.bv_val, realdn.bv_val, 0 ); 1097 rs->sr_err = LDAP_OTHER; 1098 rs->sr_text = "SQL-backend error"; 1099 e = NULL; 1100 goto done; 1101 } 1102 1103 rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 ); 1104 if ( rs->sr_err == LDAP_SUCCESS ) { 1105 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1106 "entry exists\n", 1107 op->ora_e->e_name.bv_val, 0, 0 ); 1108 rs->sr_err = LDAP_ALREADY_EXISTS; 1109 e = op->ora_e; 1110 goto done; 1111 } 1112 1113 /* 1114 * Get the parent dn and see if the corresponding entry exists. 1115 */ 1116 if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) { 1117 pdn = slap_empty_bv; 1118 1119 } else { 1120 dnParent( &op->ora_e->e_nname, &pdn ); 1121 1122 /* 1123 * Get the parent 1124 */ 1125 bsi.bsi_e = &p; 1126 rs->sr_err = backsql_init_search( &bsi, &pdn, 1127 LDAP_SCOPE_BASE, 1128 (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, 1129 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 1130 if ( rs->sr_err != LDAP_SUCCESS ) { 1131 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1132 "could not retrieve addDN parent " 1133 "\"%s\" ID - %s matched=\"%s\"\n", 1134 pdn.bv_val, 1135 rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry", 1136 rs->sr_matched ? rs->sr_matched : "(null)" ); 1137 e = &p; 1138 goto done; 1139 } 1140 1141 /* check "children" pseudo-attribute access to parent */ 1142 if ( !access_allowed( op, &p, slap_schema.si_ad_children, 1143 NULL, ACL_WADD, NULL ) ) 1144 { 1145 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1146 e = &p; 1147 goto done; 1148 } 1149 } 1150 1151 /* 1152 * create_proc is executed; if expect_return is set, then 1153 * an output parameter is bound, which should contain 1154 * the id of the added row; otherwise the procedure 1155 * is expected to return the id as the first column of a select 1156 */ 1157 rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 ); 1158 if ( rc != SQL_SUCCESS ) { 1159 rs->sr_err = LDAP_OTHER; 1160 rs->sr_text = "SQL-backend error"; 1161 e = NULL; 1162 goto done; 1163 } 1164 1165 colnum = 1; 1166 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1167 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_OUTPUT, &new_keyval ); 1168 if ( rc != SQL_SUCCESS ) { 1169 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1170 "error binding keyval parameter " 1171 "for objectClass %s\n", 1172 op->ora_e->e_name.bv_val, 1173 oc->bom_oc->soc_cname.bv_val, 0 ); 1174 backsql_PrintErrors( bi->sql_db_env, dbh, 1175 sth, rc ); 1176 SQLFreeStmt( sth, SQL_DROP ); 1177 1178 rs->sr_text = "SQL-backend error"; 1179 rs->sr_err = LDAP_OTHER; 1180 e = NULL; 1181 goto done; 1182 } 1183 colnum++; 1184 } 1185 1186 if ( oc->bom_create_hint ) { 1187 at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint ); 1188 if ( at && at->a_vals ) { 1189 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1190 at->a_vals[0].bv_val, 1191 at->a_vals[0].bv_len ); 1192 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1193 "create_proc hint: param = '%s'\n", 1194 at->a_vals[0].bv_val, 0, 0 ); 1195 1196 } else { 1197 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1198 "", 0 ); 1199 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1200 "create_proc hint (%s) not avalable\n", 1201 oc->bom_create_hint->ad_cname.bv_val, 1202 0, 0 ); 1203 } 1204 colnum++; 1205 } 1206 1207 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n", 1208 op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 ); 1209 rc = SQLExecute( sth ); 1210 if ( rc != SQL_SUCCESS ) { 1211 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1212 "create_proc execution failed\n", 1213 op->ora_e->e_name.bv_val, 0, 0 ); 1214 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1215 SQLFreeStmt( sth, SQL_DROP ); 1216 rs->sr_err = LDAP_OTHER; 1217 rs->sr_text = "SQL-backend error"; 1218 e = NULL; 1219 goto done; 1220 } 1221 1222 /* FIXME: after SQLExecute(), the row is already inserted 1223 * (at least with PostgreSQL and unixODBC); needs investigation */ 1224 1225 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1226 SWORD ncols; 1227 SQLLEN value_len; 1228 1229 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { 1230 SQLFreeStmt( sth, SQL_DROP ); 1231 1232 rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 ); 1233 if ( rc != SQL_SUCCESS ) { 1234 rs->sr_err = LDAP_OTHER; 1235 rs->sr_text = "SQL-backend error"; 1236 e = NULL; 1237 goto done; 1238 } 1239 1240 rc = SQLExecute( sth ); 1241 if ( rc != SQL_SUCCESS ) { 1242 rs->sr_err = LDAP_OTHER; 1243 rs->sr_text = "SQL-backend error"; 1244 e = NULL; 1245 goto done; 1246 } 1247 } 1248 1249 /* 1250 * the query to know the id of the inserted entry 1251 * must be embedded in the create procedure 1252 */ 1253 rc = SQLNumResultCols( sth, &ncols ); 1254 if ( rc != SQL_SUCCESS ) { 1255 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1256 "create_proc result evaluation failed\n", 1257 op->ora_e->e_name.bv_val, 0, 0 ); 1258 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1259 SQLFreeStmt( sth, SQL_DROP ); 1260 rs->sr_err = LDAP_OTHER; 1261 rs->sr_text = "SQL-backend error"; 1262 e = NULL; 1263 goto done; 1264 1265 } else if ( ncols != 1 ) { 1266 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1267 "create_proc result is bogus (ncols=%d)\n", 1268 op->ora_e->e_name.bv_val, ncols, 0 ); 1269 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1270 SQLFreeStmt( sth, SQL_DROP ); 1271 rs->sr_err = LDAP_OTHER; 1272 rs->sr_text = "SQL-backend error"; 1273 e = NULL; 1274 goto done; 1275 } 1276 1277 #if 0 1278 { 1279 SQLCHAR colname[ 64 ]; 1280 SQLSMALLINT name_len, col_type, col_scale, col_null; 1281 UDWORD col_prec; 1282 1283 /* 1284 * FIXME: check whether col_type is compatible, 1285 * if it can be null and so on ... 1286 */ 1287 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 1288 &colname[ 0 ], 1289 (SQLUINTEGER)( sizeof( colname ) - 1 ), 1290 &name_len, &col_type, 1291 &col_prec, &col_scale, &col_null ); 1292 } 1293 #endif 1294 1295 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG, 1296 (SQLPOINTER)&new_keyval, 1297 (SQLINTEGER)sizeof( new_keyval ), 1298 &value_len ); 1299 1300 rc = SQLFetch( sth ); 1301 1302 if ( value_len <= 0 ) { 1303 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1304 "create_proc result is empty?\n", 1305 op->ora_e->e_name.bv_val, 0, 0 ); 1306 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1307 SQLFreeStmt( sth, SQL_DROP ); 1308 rs->sr_err = LDAP_OTHER; 1309 rs->sr_text = "SQL-backend error"; 1310 e = NULL; 1311 goto done; 1312 } 1313 } 1314 1315 SQLFreeStmt( sth, SQL_DROP ); 1316 1317 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1318 "create_proc returned keyval=" BACKSQL_IDNUMFMT "\n", 1319 op->ora_e->e_name.bv_val, new_keyval, 0 ); 1320 1321 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 ); 1322 if ( rc != SQL_SUCCESS ) { 1323 rs->sr_err = LDAP_OTHER; 1324 rs->sr_text = "SQL-backend error"; 1325 e = NULL; 1326 goto done; 1327 } 1328 1329 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn ); 1330 if ( rc != SQL_SUCCESS ) { 1331 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1332 "error binding DN parameter for objectClass %s\n", 1333 op->ora_e->e_name.bv_val, 1334 oc->bom_oc->soc_cname.bv_val, 0 ); 1335 backsql_PrintErrors( bi->sql_db_env, dbh, 1336 sth, rc ); 1337 SQLFreeStmt( sth, SQL_DROP ); 1338 1339 rs->sr_text = "SQL-backend error"; 1340 rs->sr_err = LDAP_OTHER; 1341 e = NULL; 1342 goto done; 1343 } 1344 1345 rc = backsql_BindParamNumID( sth, 2, SQL_PARAM_INPUT, &oc->bom_id ); 1346 if ( rc != SQL_SUCCESS ) { 1347 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1348 "error binding objectClass ID parameter " 1349 "for objectClass %s\n", 1350 op->ora_e->e_name.bv_val, 1351 oc->bom_oc->soc_cname.bv_val, 0 ); 1352 backsql_PrintErrors( bi->sql_db_env, dbh, 1353 sth, rc ); 1354 SQLFreeStmt( sth, SQL_DROP ); 1355 1356 rs->sr_text = "SQL-backend error"; 1357 rs->sr_err = LDAP_OTHER; 1358 e = NULL; 1359 goto done; 1360 } 1361 1362 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id ); 1363 if ( rc != SQL_SUCCESS ) { 1364 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1365 "error binding parent ID parameter " 1366 "for objectClass %s\n", 1367 op->ora_e->e_name.bv_val, 1368 oc->bom_oc->soc_cname.bv_val, 0 ); 1369 backsql_PrintErrors( bi->sql_db_env, dbh, 1370 sth, rc ); 1371 SQLFreeStmt( sth, SQL_DROP ); 1372 1373 rs->sr_text = "SQL-backend error"; 1374 rs->sr_err = LDAP_OTHER; 1375 e = NULL; 1376 goto done; 1377 } 1378 1379 rc = backsql_BindParamNumID( sth, 4, SQL_PARAM_INPUT, &new_keyval ); 1380 if ( rc != SQL_SUCCESS ) { 1381 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1382 "error binding entry ID parameter " 1383 "for objectClass %s\n", 1384 op->ora_e->e_name.bv_val, 1385 oc->bom_oc->soc_cname.bv_val, 0 ); 1386 backsql_PrintErrors( bi->sql_db_env, dbh, 1387 sth, rc ); 1388 SQLFreeStmt( sth, SQL_DROP ); 1389 1390 rs->sr_text = "SQL-backend error"; 1391 rs->sr_err = LDAP_OTHER; 1392 e = NULL; 1393 goto done; 1394 } 1395 1396 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1397 char buf[ SLAP_TEXT_BUFLEN ]; 1398 1399 snprintf( buf, sizeof(buf), 1400 "executing \"%s\" for dn=\"%s\" oc_map_id=" BACKSQL_IDNUMFMT " p_id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDNUMFMT, 1401 bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 1402 oc->bom_id, BACKSQL_IDARG(bsi.bsi_base_id.eid_id), 1403 new_keyval ); 1404 Debug( LDAP_DEBUG_TRACE, " backsql_add(): %s\n", buf, 0, 0 ); 1405 } 1406 1407 rc = SQLExecute( sth ); 1408 if ( rc != SQL_SUCCESS ) { 1409 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1410 "could not insert ldap_entries record\n", 1411 op->ora_e->e_name.bv_val, 0, 0 ); 1412 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 1413 1414 /* 1415 * execute delete_proc to delete data added !!! 1416 */ 1417 SQLFreeStmt( sth, SQL_DROP ); 1418 rs->sr_err = LDAP_OTHER; 1419 rs->sr_text = "SQL-backend error"; 1420 e = NULL; 1421 goto done; 1422 } 1423 1424 SQLFreeStmt( sth, SQL_DROP ); 1425 1426 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 1427 Debug( LDAP_DEBUG_TRACE, " backsql_add(): " 1428 "adding attribute \"%s\"\n", 1429 at->a_desc->ad_cname.bv_val, 0, 0 ); 1430 1431 /* 1432 * Skip: 1433 * - the first occurrence of objectClass, which is used 1434 * to determine how to build the SQL entry (FIXME ?!?) 1435 * - operational attributes 1436 * - empty attributes (FIXME ?!?) 1437 */ 1438 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) { 1439 continue; 1440 } 1441 1442 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 1443 at_objectClass = at; 1444 continue; 1445 } 1446 1447 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval ); 1448 if ( rs->sr_err != LDAP_SUCCESS ) { 1449 e = op->ora_e; 1450 goto done; 1451 } 1452 } 1453 1454 if ( at_objectClass ) { 1455 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, 1456 at_objectClass, new_keyval ); 1457 if ( rs->sr_err != LDAP_SUCCESS ) { 1458 e = op->ora_e; 1459 goto done; 1460 } 1461 } 1462 1463 done:; 1464 /* 1465 * Commit only if all operations succeed 1466 */ 1467 if ( sth != SQL_NULL_HSTMT ) { 1468 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 1469 1470 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 1471 assert( e == NULL ); 1472 CompletionType = SQL_COMMIT; 1473 } 1474 1475 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 1476 } 1477 1478 /* 1479 * FIXME: NOOP does not work for add -- it works for all 1480 * the other operations, and I don't get the reason :( 1481 * 1482 * hint: there might be some autocommit in Postgres 1483 * so that when the unique id of the key table is 1484 * automatically increased, there's no rollback. 1485 * We might implement a "rollback" procedure consisting 1486 * in deleting that row. 1487 */ 1488 1489 if ( e != NULL ) { 1490 int disclose = 1; 1491 1492 if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 1493 /* mask already collected */ 1494 disclose = 0; 1495 1496 } else if ( e == &p && !access_allowed( op, &p, 1497 slap_schema.si_ad_entry, NULL, 1498 ACL_DISCLOSE, NULL ) ) 1499 { 1500 disclose = 0; 1501 } 1502 1503 if ( disclose == 0 ) { 1504 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1505 rs->sr_text = NULL; 1506 rs->sr_matched = NULL; 1507 if ( rs->sr_ref ) { 1508 ber_bvarray_free( rs->sr_ref ); 1509 rs->sr_ref = NULL; 1510 } 1511 } 1512 } 1513 1514 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 1515 rs->sr_err = LDAP_X_NO_OPERATION; 1516 } 1517 1518 send_ldap_result( op, rs ); 1519 slap_graduate_commit_csn( op ); 1520 1521 if ( !BER_BVISNULL( &realdn ) 1522 && realdn.bv_val != op->ora_e->e_name.bv_val ) 1523 { 1524 ch_free( realdn.bv_val ); 1525 } 1526 1527 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 1528 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 1529 } 1530 1531 if ( !BER_BVISNULL( &p.e_nname ) ) { 1532 backsql_entry_clean( op, &p ); 1533 } 1534 1535 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n", 1536 op->ora_e->e_name.bv_val, 1537 rs->sr_err, 1538 rs->sr_text ? rs->sr_text : "" ); 1539 1540 rs->sr_text = NULL; 1541 rs->sr_matched = NULL; 1542 if ( rs->sr_ref ) { 1543 ber_bvarray_free( rs->sr_ref ); 1544 rs->sr_ref = NULL; 1545 } 1546 1547 return rs->sr_err; 1548 } 1549 1550