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