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