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