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