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