add.c 40.5 KB
Newer Older
1
2
3
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1999-2006 The OpenLDAP Foundation.
5
 * Portions Copyright 1999 Dmitry Kovalev.
6
 * Portions Copyright 2002 Pierangelo Masarati.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 * Portions Copyright 2004 Mark Adamson.
8
9
10
11
12
13
14
15
16
17
18
19
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by Dmitry Kovalev for inclusion
20
21
22
 * by OpenLDAP Software.  Additional significant contributors include
 * Pierangelo Masarati and Mark Adamson.

23
24
25
26
27
28
29
30
31
32
33
 */

#include "portable.h"

#include <stdio.h>
#include <sys/types.h>
#include "ac/string.h"

#include "slap.h"
#include "proto-sql.h"

34
35
36
37
#ifdef BACKSQL_SYNCPROV
#include <lutil.h>
#endif /* BACKSQL_SYNCPROV */

38
39
/*
 * Skip:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
40
41
42
 * - null values (e.g. delete modification)
 * - single occurrence of objectClass, because it is already used
 *   to determine how to build the SQL entry
43
 * - operational attributes
Pierangelo Masarati's avatar
Pierangelo Masarati committed
44
 * - empty attributes
45
 */
46
47
#define backsql_opattr_skip(ad) \
	(is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
48
#define	backsql_attr_skip(ad, vals) \
49
50
	( \
		( (ad) == slap_schema.si_ad_objectClass \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
51
				&& (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
52
		|| backsql_opattr_skip( (ad) ) \
53
		|| ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
54
55
	)

56
57
58
59
60
61
62
63
64
65
int
backsql_modify_delete_all_values(
	Operation 		*op,
	SlapReply		*rs,
	SQLHDBC			dbh, 
	backsql_entryID		*e_id,
	backsql_at_map_rec	*at )
{
	backsql_info	*bi = (backsql_info *)op->o_bd->be_private;
	RETCODE		rc;
66
	SQLHSTMT	asth = SQL_NULL_HSTMT;
67
68
	BACKSQL_ROW_NTS	row;

69
	assert( at != NULL );
70
71
72
73
74
75
76
77
78
79
80
81
82
83
	if ( at->bam_delete_proc == NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
			"missing attribute value delete procedure "
			"for attr \"%s\"\n",
			at->bam_ad->ad_cname.bv_val, 0, 0 );
		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
		}

		return LDAP_SUCCESS;
	}

84
85
86
87
	rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
88
89
90
			"error preparing attribute value select query "
			"\"%s\"\n",
			at->bam_query, 0, 0 );
91
		backsql_PrintErrors( bi->sql_db_env, dbh, 
92
93
				asth, rc );

94
95
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
96
97
	}

98
	rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval );
99
100
101
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
102
103
			"error binding key value parameter "
			"to attribute value select query\n",
104
			0, 0, 0 );
105
		backsql_PrintErrors( bi->sql_db_env, dbh, 
106
107
108
				asth, rc );
		SQLFreeStmt( asth, SQL_DROP );

109
110
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
111
112
113
114
115
116
	}
			
	rc = SQLExecute( asth );
	if ( !BACKSQL_SUCCESS( rc ) ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
117
			"error executing attribute value select query\n",
118
			0, 0, 0 );
119
		backsql_PrintErrors( bi->sql_db_env, dbh, 
120
121
122
				asth, rc );
		SQLFreeStmt( asth, SQL_DROP );

123
124
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
125
126
	}

127
	backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx );
128
129
130
131
	for ( rc = SQLFetch( asth );
			BACKSQL_SUCCESS( rc );
			rc = SQLFetch( asth ) )
	{
132
		int		i;
133
		/* first parameter no, parameter order */
134
		SQLUSMALLINT	pno = 0,
135
				po = 0;
136
		/* procedure return code */
137
		int		prc = LDAP_SUCCESS;
138
139
		
		for ( i = 0; i < row.ncols; i++ ) {
140
			SQLHSTMT	sth = SQL_NULL_HSTMT;
141
			ber_len_t	col_len;
142
143
144
145
146
			
			rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
147
148
149
					"error preparing attribute value "
					"delete procedure "
					"\"%s\"\n",
150
					at->bam_delete_proc, 0, 0 );
151
				backsql_PrintErrors( bi->sql_db_env, dbh, 
152
153
						sth, rc );

154
				rs->sr_text = "SQL-backend error";
155
156
				rs->sr_err = LDAP_OTHER;
				goto done;
157
158
159
160
			}

	   		if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
				pno = 1;
161
162
163
164
165
166
167
				rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_delete_all_values(): "
						"error binding output parameter for %s[%d]\n",
						at->bam_ad->ad_cname.bv_val, i, 0 );
168
					backsql_PrintErrors( bi->sql_db_env, dbh, 
169
170
171
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

172
					rs->sr_text = "SQL-backend error";
173
174
					rs->sr_err = LDAP_OTHER;
					goto done;
175
				}
176
177
			}
			po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
178
179
180
181
182
183
184
			rc = backsql_BindParamID( sth, pno + 1 + po,
				SQL_PARAM_INPUT, &e_id->eid_keyval );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"error binding keyval parameter for %s[%d]\n",
					at->bam_ad->ad_cname.bv_val, i, 0 );
185
				backsql_PrintErrors( bi->sql_db_env, dbh, 
186
187
188
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

189
				rs->sr_text = "SQL-backend error";
190
191
				rs->sr_err = LDAP_OTHER;
				goto done;
192
			}
193
194
#ifdef BACKSQL_ARBITRARY_KEY
			Debug( LDAP_DEBUG_TRACE,
195
				"   backsql_modify_delete_all_values() "
196
				"arg(%d)=%s\n",
197
198
199
				pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
#else /* ! BACKSQL_ARBITRARY_KEY */
			Debug( LDAP_DEBUG_TRACE,
200
				"   backsql_modify_delete_all_values() "
201
				"arg(%d)=%lu\n",
202
203
204
205
206
207
208
				pno + 1 + po, e_id->eid_keyval, 0 );
#endif /* ! BACKSQL_ARBITRARY_KEY */

			/*
			 * check for syntax needed here 
			 * maybe need binary bind?
			 */
209
			col_len = strlen( row.cols[ i ] );
210
211
212
213
214
215
216
			rc = backsql_BindParamStr( sth, pno + 2 - po,
				SQL_PARAM_INPUT, row.cols[ i ], col_len );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"error binding value parameter for %s[%d]\n",
					at->bam_ad->ad_cname.bv_val, i, 0 );
217
				backsql_PrintErrors( bi->sql_db_env, dbh, 
218
219
220
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

221
				rs->sr_text = "SQL-backend error";
222
223
				rs->sr_err = LDAP_OTHER;
				goto done;
224
			}
225
226
227
	 
			Debug( LDAP_DEBUG_TRACE, 
				"   backsql_modify_delete_all_values(): "
228
				"arg(%d)=%s; executing \"%s\"\n",
229
230
231
				pno + 2 - po, row.cols[ i ],
				at->bam_delete_proc );
			rc = SQLExecute( sth );
232
233
234
235
			if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
				rs->sr_err = LDAP_SUCCESS;

			} else {
236
237
238
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"delete_proc "
239
240
241
242
243
244
245
246
247
248
					"execution failed (rc=%d, prc=%d)\n",
					rc, prc, 0 );
				if ( prc != LDAP_SUCCESS ) {
					/* SQL procedure executed fine 
					 * but returned an error */
					rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );

				} else {
					backsql_PrintErrors( bi->sql_db_env, dbh,
							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
256
257
			}
			SQLFreeStmt( sth, SQL_DROP );
		}
	}
258
259
260
261
262

	rs->sr_err = LDAP_SUCCESS;

done:;
	backsql_FreeRow_x( &row, op->o_tmpmemctx );
263
264
	SQLFreeStmt( asth, SQL_DROP );

265
	return rs->sr_err;
266
267
}

268
269
270
271
272
273
274
275
276
int
backsql_modify_internal(
	Operation 		*op,
	SlapReply		*rs,
	SQLHDBC			dbh, 
	backsql_oc_map_rec	*oc,
	backsql_entryID		*e_id,
	Modifications		*modlist )
{
277
	backsql_info	*bi = (backsql_info *)op->o_bd->be_private;
278
279
280
281
282
283
284
285
	RETCODE		rc;
	Modifications	*ml;

	Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
		"traversing modifications list\n", 0, 0, 0 );

	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		AttributeDescription	*ad;
286
287
288
289
290
		int			sm_op;
		static char		*sm_ops[] = { "add", "delete", "replace", "increment", NULL };

		BerVarray		sm_values;
#if 0
Pierangelo Masarati's avatar
Pierangelo Masarati committed
291
		/* NOTE: some day we'll have to pass 
292
		 * the normalized values as well */
293
		BerVarray		sm_nvalues;
294
#endif
295
296
297
		backsql_at_map_rec	*at = NULL;
		struct berval		*at_val;
		int			i;
298
		
299
300
301
302
303
304
		ad = ml->sml_mod.sm_desc;
		sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
		sm_values = ml->sml_mod.sm_values;
#if 0
		sm_nvalues = ml->sml_mod.sm_nvalues;
#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
313
314
315
316
317
318
319
			continue;
		}

  		at = backsql_ad2at( oc, ad );
		if ( at == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"attribute \"%s\" is not registered "
				"in objectClass \"%s\"\n",
320
				ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
321
322
323
324
325
326
327
328
329
330
331

			if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
				rs->sr_text = "operation not permitted "
					"within namingContext";
				goto done;
			}

			continue;
		}
  
332
		switch ( sm_op ) {
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
		case LDAP_MOD_REPLACE: {
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"replacing values for attribute \"%s\"\n",
				at->bam_ad->ad_cname.bv_val, 0, 0 );

			if ( at->bam_add_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"add procedure is not defined "
					"for attribute \"%s\" "
					"- unable to perform replacements\n",
					at->bam_ad->ad_cname.bv_val, 0, 0 );

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}

			if ( at->bam_delete_proc == NULL ) {
				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"delete procedure is not defined "
						"for attribute \"%s\"\n",
						at->bam_ad->ad_cname.bv_val, 0, 0 );

					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"delete procedure is not defined "
					"for attribute \"%s\" "
					"- adding only\n",
					at->bam_ad->ad_cname.bv_val, 0, 0 );

				goto add_only;
			}
379

380
del_all:
381
382
383
			rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				goto done;
384
			}
385
386

			/* LDAP_MOD_DELETE gets here if all values must be deleted */
387
			if ( sm_op == LDAP_MOD_DELETE ) {
388
389
				break;
			}
390
391
392
393
394
395
	       	}

		/*
		 * PASSTHROUGH - to add new attributes -- do NOT add break
		 */
		case LDAP_MOD_ADD:
396
		/* case SLAP_MOD_SOFTADD: */
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
add_only:;
			if ( at->bam_add_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"add procedure is not defined "
					"for attribute \"%s\"\n",
					at->bam_ad->ad_cname.bv_val, 0, 0 );

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}
			
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"adding new values for attribute \"%s\"\n",
				at->bam_ad->ad_cname.bv_val, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
418
419
420
421

			/* can't add a NULL val array */
			assert( sm_values != NULL );
			
422
423
424
425
			for ( i = 0, at_val = sm_values;
					!BER_BVISNULL( at_val ); 
					i++, at_val++ )
			{
426
427
428
429
430
431
432
				SQLHSTMT	sth = SQL_NULL_HSTMT;
				/* first parameter position, parameter order */
				SQLUSMALLINT	pno = 0,
						po;
				/* procedure return code */
				int		prc = LDAP_SUCCESS;

433
434
435
436
437
438
				rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error preparing add query\n", 
						0, 0, 0 );
439
					backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
440
441
442
443
444
445

					rs->sr_err = LDAP_OTHER;
					rs->sr_text = "SQL-backend error";
					goto done;
				}

446
447
				if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
					pno = 1;
448
449
450
451
452
453
454
	      				rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
					if ( rc != SQL_SUCCESS ) {
						Debug( LDAP_DEBUG_TRACE,
							"   backsql_modify_internal(): "
							"error binding output parameter for %s[%d]\n",
							at->bam_ad->ad_cname.bv_val, i, 0 );
455
						backsql_PrintErrors( bi->sql_db_env, dbh, 
456
457
458
459
460
461
462
							sth, rc );
						SQLFreeStmt( sth, SQL_DROP );

						rs->sr_text = "SQL-backend error";
						rs->sr_err = LDAP_OTHER;
						goto done;
					}
463
464
				}
				po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
465
466
467
468
469
470
471
				rc = backsql_BindParamID( sth, pno + 1 + po,
					SQL_PARAM_INPUT, &e_id->eid_keyval );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding keyval parameter for %s[%d]\n",
						at->bam_ad->ad_cname.bv_val, i, 0 );
472
					backsql_PrintErrors( bi->sql_db_env, dbh, 
473
474
475
476
477
478
479
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
480
#ifdef BACKSQL_ARBITRARY_KEY
481
482
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
483
					"arg(%d)=\"%s\"\n", 
484
					pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
485
#else /* ! BACKSQL_ARBITRARY_KEY */
486
487
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
488
					"arg(%d)=\"%lu\"\n", 
489
					pno + 1 + po, e_id->eid_keyval, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
490
#endif /* ! BACKSQL_ARBITRARY_KEY */
491
492
493
494
495

				/*
				 * check for syntax needed here
				 * maybe need binary bind?
				 */
496
497
498
499
500
501
502
				rc = backsql_BindParamBerVal( sth, pno + 2 - po,
					SQL_PARAM_INPUT, at_val );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding value parameter for %s[%d]\n",
						at->bam_ad->ad_cname.bv_val, i, 0 );
503
					backsql_PrintErrors( bi->sql_db_env, dbh, 
504
505
506
507
508
509
510
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
511
512
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
513
					"arg(%d)=\"%s\"; executing \"%s\"\n", 
514
515
516
					pno + 2 - po, at_val->bv_val,
					at->bam_add_proc );

517
				rc = SQLExecute( sth );
518
519
520
521
				if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
					rs->sr_err = LDAP_SUCCESS;

				} else {
522
523
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
524
525
526
527
528
529
530
						"add_proc execution failed "
						"(rc=%d, prc=%d)\n",
						rc, prc, 0 );
					if ( prc != LDAP_SUCCESS ) {
						/* SQL procedure executed fine 
						 * but returned an error */
						SQLFreeStmt( sth, SQL_DROP );
531

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
						rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
						return rs->sr_err;
					
					} else {
						backsql_PrintErrors( bi->sql_db_env, dbh,
								sth, rc );
						if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 
						{
							SQLFreeStmt( sth, SQL_DROP );

							rs->sr_err = LDAP_OTHER;
							rs->sr_text = "SQL-backend error";
							goto done;
						}
					}
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
				}
				SQLFreeStmt( sth, SQL_DROP );
			}
			break;
			
	      	case LDAP_MOD_DELETE:
			if ( at->bam_delete_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"delete procedure is not defined "
					"for attribute \"%s\"\n",
					at->bam_ad->ad_cname.bv_val, 0, 0 );

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}

571
			if ( sm_values == NULL ) {
572
573
574
575
576
577
578
579
580
581
582
583
584
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"no values given to delete "
					"for attribute \"%s\" "
					"-- deleting all values\n",
					at->bam_ad->ad_cname.bv_val, 0, 0 );
				goto del_all;
			}

			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"deleting values for attribute \"%s\"\n",
				at->bam_ad->ad_cname.bv_val, 0, 0 );

585
586
587
588
			for ( i = 0, at_val = sm_values;
					!BER_BVISNULL( at_val );
					i++, at_val++ )
			{
589
590
591
592
593
594
595
				SQLHSTMT	sth = SQL_NULL_HSTMT;
				/* first parameter position, parameter order */
				SQLUSMALLINT	pno = 0,
						po;
				/* procedure return code */
				int		prc = LDAP_SUCCESS;

596
597
598
599
600
601
				rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error preparing delete query\n", 
						0, 0, 0 );
602
					backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
603
604
605
606
607
608

					rs->sr_err = LDAP_OTHER;
					rs->sr_text = "SQL-backend error";
					goto done;
				}

609
610
				if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
					pno = 1;
611
612
613
614
615
616
617
					rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
					if ( rc != SQL_SUCCESS ) {
						Debug( LDAP_DEBUG_TRACE,
							"   backsql_modify_internal(): "
							"error binding output parameter for %s[%d]\n",
							at->bam_ad->ad_cname.bv_val, i, 0 );
618
						backsql_PrintErrors( bi->sql_db_env, dbh, 
619
620
621
622
623
624
625
							sth, rc );
						SQLFreeStmt( sth, SQL_DROP );

						rs->sr_text = "SQL-backend error";
						rs->sr_err = LDAP_OTHER;
						goto done;
					}
626
627
				}
				po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
628
629
630
631
632
633
634
				rc = backsql_BindParamID( sth, pno + 1 + po,
					SQL_PARAM_INPUT, &e_id->eid_keyval );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding keyval parameter for %s[%d]\n",
						at->bam_ad->ad_cname.bv_val, i, 0 );
635
					backsql_PrintErrors( bi->sql_db_env, dbh, 
636
637
638
639
640
641
642
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
643
#ifdef BACKSQL_ARBITRARY_KEY
644
645
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
646
					"arg(%d)=\"%s\"\n", 
647
					pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
648
#else /* ! BACKSQL_ARBITRARY_KEY */
649
650
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
651
					"arg(%d)=\"%lu\"\n", 
652
					pno + 1 + po, e_id->eid_keyval, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
653
#endif /* ! BACKSQL_ARBITRARY_KEY */
654
655
656
657
658

				/*
				 * check for syntax needed here 
				 * maybe need binary bind?
				 */
659
660
661
662
663
664
665
				rc = backsql_BindParamBerVal( sth, pno + 2 - po,
					SQL_PARAM_INPUT, at_val );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding value parameter for %s[%d]\n",
						at->bam_ad->ad_cname.bv_val, i, 0 );
666
					backsql_PrintErrors( bi->sql_db_env, dbh, 
667
668
669
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

670
671
672
					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
673
				}
674
675
676
677
678

				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"executing \"%s\"\n", 
					at->bam_delete_proc, 0, 0 );
679
				rc = SQLExecute( sth );
680
681
682
683
684
				if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS )
				{
					rs->sr_err = LDAP_SUCCESS;
					
				} else {
685
686
687
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"delete_proc execution "
688
689
690
691
692
693
694
695
						"failed (rc=%d, prc=%d)\n",
						rc, prc, 0 );

					if ( prc != LDAP_SUCCESS ) {
						/* SQL procedure executed fine
						 * but returned an error */
						rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
696
						goto done;
697
698
699
700
						
					} else {
						backsql_PrintErrors( bi->sql_db_env,
								dbh, sth, rc );
701
702
703
704
						SQLFreeStmt( sth, SQL_DROP );
						rs->sr_err = LDAP_OTHER;
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
						goto done;
705
706
707
					}
				}
				SQLFreeStmt( sth, SQL_DROP );
708
709
710
711
712
713
714
715
716
717
			}
			break;

	      	case LDAP_MOD_INCREMENT:
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"increment not supported yet\n", 0, 0, 0 );
			if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "SQL-backend error";
				goto done;
718
719
720
721
722
723
			}
			break;
		}
	}

done:;
724
725
726
	Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n",
		rs->sr_err,
		rs->sr_text ? ": " : "",
727
728
729
730
731
732
733
734
		rs->sr_text ? rs->sr_text : "" );

	/*
	 * FIXME: should fail in case one change fails?
	 */
	return rs->sr_err;
}

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
static int
backsql_add_attr(
	Operation		*op,
	SlapReply		*rs,
	SQLHDBC 		dbh,
	backsql_oc_map_rec 	*oc,
	Attribute		*at,
	unsigned long		new_keyval )
{
	backsql_info		*bi = (backsql_info*)op->o_bd->be_private;
	backsql_at_map_rec	*at_rec = NULL;
	struct berval		*at_val;
	unsigned long		i;
	RETCODE			rc;
	SQLUSMALLINT		currpos;
750
	SQLHSTMT 		sth = SQL_NULL_HSTMT;
751
752
753
754

	at_rec = backsql_ad2at( oc, at->a_desc ); 
  
	if ( at_rec == NULL ) {
755
		Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
756
757
			"attribute \"%s\" is not registered "
			"in objectclass \"%s\"\n",
758
			op->ora_e->e_name.bv_val,
759
760
761
762
763
764
765
766
767
768
769
770
771
			at->a_desc->ad_cname.bv_val,
			BACKSQL_OC_NAME( oc ) );

		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "operation not permitted "
				"within namingContext";
			return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		}

		return LDAP_SUCCESS;
	}
	
	if ( at_rec->bam_add_proc == NULL ) {
772
		Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
773
774
775
			"add procedure is not defined "
			"for attribute \"%s\" "
			"of structuralObjectClass \"%s\"\n",
776
			op->ora_e->e_name.bv_val,
777
778
779
780
781
782
783
784
785
786
787
788
789
			at->a_desc->ad_cname.bv_val,
			BACKSQL_OC_NAME( oc ) );

		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "operation not permitted "
				"within namingContext";
			return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		}

		return LDAP_SUCCESS;
	}

	for ( i = 0, at_val = &at->a_vals[ i ];
790
		       	!BER_BVISNULL( at_val );
791
792
			i++, at_val = &at->a_vals[ i ] )
	{
793
794
795
796
797
		/* procedure return code */
		int		prc = LDAP_SUCCESS;
		/* first parameter #, parameter order */
		SQLUSMALLINT	pno, po;
		char		logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
798
799
800
801
802
803
		
		/*
		 * Do not deal with the objectClass that is used
		 * to build the entry
		 */
		if ( at->a_desc == slap_schema.si_ad_objectClass ) {
804
			if ( dn_match( at_val, &oc->bom_oc->soc_cname ) )
805
806
807
808
809
			{
				continue;
			}
		}

810
		rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
811
		if ( rc != SQL_SUCCESS ) {
812
813
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
814
815
816
817
		}

		if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
			pno = 1;
818
819
820
821
			rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_add_attr(): "
822
					"error binding output parameter for %s[%lu]\n",
823
					at_rec->bam_ad->ad_cname.bv_val, i, 0 );
824
				backsql_PrintErrors( bi->sql_db_env, dbh, 
825
826
827
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

828
829
				rs->sr_text = "SQL-backend error";
				return rs->sr_err = LDAP_OTHER;
830
831
			}

832
833
834
835
836
837
		} else {
			pno = 0;
		}

		po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
		currpos = pno + 1 + po;
838
839
840
841
842
		rc = backsql_BindParamInt( sth, currpos,
				SQL_PARAM_INPUT, &new_keyval );
		if ( rc != SQL_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE,
				"   backsql_add_attr(): "
843
				"error binding keyval parameter for %s[%lu]\n",
844
				at_rec->bam_ad->ad_cname.bv_val, i, 0 );
845
			backsql_PrintErrors( bi->sql_db_env, dbh, 
846
847
848
				sth, rc );
			SQLFreeStmt( sth, SQL_DROP );

849
850
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
851
852
		}

853
854
855
856
857
858
859
		currpos = pno + 2 - po;

		/*
		 * check for syntax needed here 
		 * maybe need binary bind?
		 */

860
861
862
863
		rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val );
		if ( rc != SQL_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE,
				"   backsql_add_attr(): "
864
				"error binding value parameter for %s[%lu]\n",
865
				at_rec->bam_ad->ad_cname.bv_val, i, 0 );
866
			backsql_PrintErrors( bi->sql_db_env, dbh, 
867
868
869
				sth, rc );
			SQLFreeStmt( sth, SQL_DROP );

870
871
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
872
		}
873
874

#ifdef LDAP_DEBUG
875
		snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=%lu",
876
				i, new_keyval );
877
		Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
878
			"executing \"%s\" %s\n", 
879
			op->ora_e->e_name.bv_val,
880
881
			at_rec->bam_add_proc, logbuf );
#endif
882
		rc = SQLExecute( sth );
883
884
885
886
		if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
			rs->sr_err = LDAP_SUCCESS;

		} else {
887
			Debug( LDAP_DEBUG_TRACE,
888
				"   backsql_add_attr(\"%s\"): "
889
				"add_proc execution failed (rc=%d, prc=%d)\n", 
890
				op->ora_e->e_name.bv_val, rc, prc );
891
892
893
894
			if ( prc != LDAP_SUCCESS ) {
				/* SQL procedure executed fine
				 * but returned an error */
				rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
895
				rs->sr_text = op->ora_e->e_name.bv_val;
896
				SQLFreeStmt( sth, SQL_DROP );
897
898
899
900
901
				return rs->sr_err;

			} else {
				backsql_PrintErrors( bi->sql_db_env, dbh,
						sth, rc );
902
903
904
905
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = op->ora_e->e_name.bv_val;
				SQLFreeStmt( sth, SQL_DROP );
				return rs->sr_err;
906
907
			}
		}
908
		SQLFreeStmt( sth, SQL_DROP );
909
910
911
912
913
	}

	return LDAP_SUCCESS;
}

914
915
916
917
int
backsql_add( Operation *op, SlapReply *rs )
{
	backsql_info		*bi = (backsql_info*)op->o_bd->be_private;
918
919
	SQLHDBC 		dbh = SQL_NULL_HDBC;
	SQLHSTMT 		sth = SQL_NULL_HSTMT;
920
921
922
	unsigned long		new_keyval = 0;
	RETCODE			rc;
	backsql_oc_map_rec 	*oc = NULL;
923
	backsql_srch_info	bsi = { 0 };
924
	Entry			p = { 0 }, *e = NULL;
925
926
	Attribute		*at,
				*at_objectClass = NULL;
927
	ObjectClass		*soc = NULL;
928
	struct berval		scname = BER_BVNULL;
929
	struct berval		pdn;
930
	struct berval		realdn = BER_BVNULL;
931
	int			colnum;
932
	slap_mask_t		mask;
933

934
935
936
	char			textbuf[ SLAP_TEXT_BUFLEN ];
	size_t			textlen = sizeof( textbuf );

937
938
939
940
941
942
#ifdef BACKSQL_SYNCPROV
	/*
	 * NOTE: fake successful result to force contextCSN to be bumped up
	 */
	if ( op->o_sync ) {
		char		buf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
Howard Chu's avatar
Howard Chu committed
943
		struct berval	csn;
944

Howard Chu's avatar
Howard Chu committed
945
946
947
		csn.bv_val = buf;
		csn.bv_len = sizeof( buf );
		slap_get_csn( op, &csn, 1 );
948
949
950
951
952
953
954
955
956
957

		rs->sr_err = LDAP_SUCCESS;
		send_ldap_result( op, rs );

		slap_graduate_commit_csn( op );

		return 0;
	}
#endif /* BACKSQL_SYNCPROV */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
958
	Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
959
			op->ora_e->e_name.bv_val, 0, 0 );
960
961

	/* check schema */
962
	if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
963
964
		char		textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };

965
		rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1,
966
			&rs->sr_text, textbuf, sizeof( textbuf ) );
967
		if ( rs->sr_err != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
968
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
969
				"entry failed schema check -- aborting\n",
970
971
				op->ora_e->e_name.bv_val, 0, 0 );
			e = NULL;
972
973
974
975
			goto done;
		}
	}

976
977
	slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );

978
	/* search structuralObjectClass */
979
	for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
980
981
982
983
984
985
		if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
			break;
		}
	}

	/* there must exist */
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
	if ( at == NULL ) {
		char		buf[ SLAP_TEXT_BUFLEN ];
		const char	*text;

		/* search structuralObjectClass */
		for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
			if ( at->a_desc == slap_schema.si_ad_objectClass ) {
				break;
			}
		}

		if ( at == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
				"no objectClass\n",
				op->ora_e->e_name.bv_val, 0, 0 );
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			e = NULL;
			goto done;
		}

1006
		rs->sr_err = structural_class( at->a_vals, &soc, NULL,
1007
				&text, buf, sizeof( buf ), op->o_tmpmemctx );
1008
1009
1010
1011
1012
1013
1014
		if ( rs->sr_err != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
				"%s (%d)\n",
				op->ora_e->e_name.bv_val, text, rs->sr_err );
			e = NULL;
			goto done;
		}
1015
		scname = soc->soc_cname;
1016
1017
1018
1019

	} else {
		scname = at->a_vals[0];
	}
1020
1021

	/* I guess we should play with sub/supertypes to find a suitable oc */
1022
	oc = backsql_name2oc( bi, &scname );
1023
1024

	if ( oc == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1025
1026
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"cannot map structuralObjectClass \"%s\" -- aborting\n",
1027
			op->ora_e->e_name.bv_val,
1028
			scname.bv_val, 0 );
1029
1030
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1031
		e = NULL;
1032
1033
1034
1035
		goto done;
	}

	if ( oc->bom_create_proc == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1036
1037
1038
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"create procedure is not defined "
			"for structuralObjectClass \"%s\" - aborting\n",
1039
			op->ora_e->e_name.bv_val,
1040
			scname.bv_val, 0 );
1041
1042
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1043
		e = NULL;
1044
1045
1046
1047
		goto done;

	} else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
			&& oc->bom_create_keyval == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1048
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1049
			"create procedure needs select procedure, "
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1050
1051
			"but none is defined for structuralObjectClass \"%s\" "
			"- aborting\n",
1052
			op->ora_e->e_name.bv_val,
1053
			scname.bv_val, 0 );
1054
1055
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1056
		e = NULL;
1057
1058
1059
		goto done;
	}

1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
	/* check write access */
	if ( !access_allowed_mask( op, op->ora_e,
				slap_schema.si_ad_entry,
				NULL, ACL_WADD, NULL, &mask ) )
	{
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		e = op->ora_e;
		goto done;
	}

1070
1071
	rs->sr_err = backsql_get_db_conn( op, &dbh );
	if ( rs->sr_err != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1072
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1073
			"could not get connection handle - exiting\n", 
1074
			op->ora_e->e_name.bv_val, 0, 0 );
1075
1076
		rs->sr_text = ( rs->sr_err == LDAP_OTHER )
			?  "SQL-backend error" : NULL;
1077
		e = NULL;
1078
1079
1080
1081
1082
		goto done;
	}

	/*
	 * Check if entry exists
1083
	 *
1084
1085
	 * NOTE: backsql_api_dn2odbc() is called explicitly because
	 * we need the mucked DN to pass it to the create procedure.
1086
	 */
1087
	realdn = op->ora_e->e_name;
1088
	if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1089
1090
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"backsql_api_dn2odbc(\"%s\") failed\n", 
1091
			op->ora_e->e_name.bv_val, realdn.bv_val, 0 );
1092
1093
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "SQL-backend error";
1094
		e = NULL;
1095
1096
1097
		goto done;
	}

1098
	rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 );
1099
	if ( rs->sr_err == LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1100
1101
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"entry exists\n",
1102
			op->ora_e->e_name.bv_val, 0, 0 );
1103
		rs->sr_err = LDAP_ALREADY_EXISTS;
1104
		e = op->ora_e;
1105
1106
1107
1108
		goto done;
	}

	/*
1109
	 * Get the parent dn and see if the corresponding entry exists.
1110
	 */
1111
	if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
1112
		pdn = slap_empty_bv;
1113

1114
	} else {
1115
		dnParent( &op->ora_e->e_nname, &pdn );
1116

1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
		/*
		 * Get the parent
		 */
		bsi.bsi_e = &p;
		rs->sr_err = backsql_init_search( &bsi, &pdn,
				LDAP_SCOPE_BASE, 
				(time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
				( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
				"could not retrieve addDN parent "
				"\"%s\" ID - %s matched=\"%s\"\n", 
				pdn.bv_val,
				rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry",
				rs->sr_matched ? rs->sr_matched : "(null)" );
			e = &p;
			goto done;
		}
1135

1136
1137
1138
1139
1140
1141
1142
1143
		/* check "children" pseudo-attribute access to parent */
		if ( !access_allowed( op, &p, slap_schema.si_ad_children,
					NULL, ACL_WADD, NULL ) )
		{
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
			e = &p;
			goto done;
		}
1144
1145
	}

1146
1147
1148
1149
1150
1151
	/*
	 * create_proc is executed; if expect_return is set, then
	 * an output parameter is bound, which should contain 
	 * the id of the added row; otherwise the procedure
	 * is expected to return the id as the first column of a select
	 */
1152
	rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 );
1153
1154
1155
	if ( rc != SQL_SUCCESS ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "SQL-backend error";
1156
		e = NULL;
1157
1158
1159
		goto done;
	}

1160
	colnum = 1;
1161
	if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1162
1163
		rc = backsql_BindParamInt( sth, 1