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