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