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