]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/add.c
ae88f76e4938b4fc0215c4f5db04a3153ce57439
[openldap] / servers / slapd / back-sql / add.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2009 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, NULL,
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         if ( get_assert( op ) &&
979                 ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
980         {
981                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
982                         "assertion control failed -- aborting\n",
983                         op->ora_e->e_name.bv_val, 0, 0 );
984                 e = NULL;
985                 rs->sr_err = LDAP_ASSERTION_FAILED;
986                 goto done;
987         }
988
989         /* search structuralObjectClass */
990         for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
991                 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
992                         break;
993                 }
994         }
995
996         /* there must exist */
997         if ( at == NULL ) {
998                 char            buf[ SLAP_TEXT_BUFLEN ];
999                 const char      *text;
1000
1001                 /* search structuralObjectClass */
1002                 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
1003                         if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1004                                 break;
1005                         }
1006                 }
1007
1008                 if ( at == NULL ) {
1009                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1010                                 "no objectClass\n",
1011                                 op->ora_e->e_name.bv_val, 0, 0 );
1012                         rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
1013                         e = NULL;
1014                         goto done;
1015                 }
1016
1017                 rs->sr_err = structural_class( at->a_vals, &soc, NULL,
1018                                 &text, buf, sizeof( buf ), op->o_tmpmemctx );
1019                 if ( rs->sr_err != LDAP_SUCCESS ) {
1020                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1021                                 "%s (%d)\n",
1022                                 op->ora_e->e_name.bv_val, text, rs->sr_err );
1023                         e = NULL;
1024                         goto done;
1025                 }
1026                 scname = soc->soc_cname;
1027
1028         } else {
1029                 scname = at->a_vals[0];
1030         }
1031
1032         /* I guess we should play with sub/supertypes to find a suitable oc */
1033         oc = backsql_name2oc( bi, &scname );
1034
1035         if ( oc == NULL ) {
1036                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1037                         "cannot map structuralObjectClass \"%s\" -- aborting\n",
1038                         op->ora_e->e_name.bv_val,
1039                         scname.bv_val, 0 );
1040                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1041                 rs->sr_text = "operation not permitted within namingContext";
1042                 e = NULL;
1043                 goto done;
1044         }
1045
1046         if ( oc->bom_create_proc == NULL ) {
1047                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1048                         "create procedure is not defined "
1049                         "for structuralObjectClass \"%s\" - aborting\n",
1050                         op->ora_e->e_name.bv_val,
1051                         scname.bv_val, 0 );
1052                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1053                 rs->sr_text = "operation not permitted within namingContext";
1054                 e = NULL;
1055                 goto done;
1056
1057         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
1058                         && oc->bom_create_keyval == NULL ) {
1059                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1060                         "create procedure needs select procedure, "
1061                         "but none is defined for structuralObjectClass \"%s\" "
1062                         "- aborting\n",
1063                         op->ora_e->e_name.bv_val,
1064                         scname.bv_val, 0 );
1065                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1066                 rs->sr_text = "operation not permitted within namingContext";
1067                 e = NULL;
1068                 goto done;
1069         }
1070
1071         /* check write access */
1072         if ( !access_allowed_mask( op, op->ora_e,
1073                                 slap_schema.si_ad_entry,
1074                                 NULL, ACL_WADD, NULL, &mask ) )
1075         {
1076                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1077                 e = op->ora_e;
1078                 goto done;
1079         }
1080
1081         rs->sr_err = backsql_get_db_conn( op, &dbh );
1082         if ( rs->sr_err != LDAP_SUCCESS ) {
1083                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1084                         "could not get connection handle - exiting\n", 
1085                         op->ora_e->e_name.bv_val, 0, 0 );
1086                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
1087                         ?  "SQL-backend error" : NULL;
1088                 e = NULL;
1089                 goto done;
1090         }
1091
1092         /*
1093          * Check if entry exists
1094          *
1095          * NOTE: backsql_api_dn2odbc() is called explicitly because
1096          * we need the mucked DN to pass it to the create procedure.
1097          */
1098         realdn = op->ora_e->e_name;
1099         if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
1100                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1101                         "backsql_api_dn2odbc(\"%s\") failed\n", 
1102                         op->ora_e->e_name.bv_val, realdn.bv_val, 0 );
1103                 rs->sr_err = LDAP_OTHER;
1104                 rs->sr_text = "SQL-backend error";
1105                 e = NULL;
1106                 goto done;
1107         }
1108
1109         rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 );
1110         if ( rs->sr_err == LDAP_SUCCESS ) {
1111                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1112                         "entry exists\n",
1113                         op->ora_e->e_name.bv_val, 0, 0 );
1114                 rs->sr_err = LDAP_ALREADY_EXISTS;
1115                 e = op->ora_e;
1116                 goto done;
1117         }
1118
1119         /*
1120          * Get the parent dn and see if the corresponding entry exists.
1121          */
1122         if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
1123                 pdn = slap_empty_bv;
1124
1125         } else {
1126                 dnParent( &op->ora_e->e_nname, &pdn );
1127
1128                 /*
1129                  * Get the parent
1130                  */
1131                 bsi.bsi_e = &p;
1132                 rs->sr_err = backsql_init_search( &bsi, &pdn,
1133                                 LDAP_SCOPE_BASE, 
1134                                 (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
1135                                 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
1136                 if ( rs->sr_err != LDAP_SUCCESS ) {
1137                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1138                                 "could not retrieve addDN parent "
1139                                 "\"%s\" ID - %s matched=\"%s\"\n", 
1140                                 pdn.bv_val,
1141                                 rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry",
1142                                 rs->sr_matched ? rs->sr_matched : "(null)" );
1143                         e = &p;
1144                         goto done;
1145                 }
1146
1147                 /* check "children" pseudo-attribute access to parent */
1148                 if ( !access_allowed( op, &p, slap_schema.si_ad_children,
1149                                         NULL, ACL_WADD, NULL ) )
1150                 {
1151                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1152                         e = &p;
1153                         goto done;
1154                 }
1155         }
1156
1157         /*
1158          * create_proc is executed; if expect_return is set, then
1159          * an output parameter is bound, which should contain 
1160          * the id of the added row; otherwise the procedure
1161          * is expected to return the id as the first column of a select
1162          */
1163         rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 );
1164         if ( rc != SQL_SUCCESS ) {
1165                 rs->sr_err = LDAP_OTHER;
1166                 rs->sr_text = "SQL-backend error";
1167                 e = NULL;
1168                 goto done;
1169         }
1170
1171         colnum = 1;
1172         if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1173                 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval );
1174                 if ( rc != SQL_SUCCESS ) {
1175                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1176                                 "error binding keyval parameter "
1177                                 "for objectClass %s\n",
1178                                 op->ora_e->e_name.bv_val,
1179                                 oc->bom_oc->soc_cname.bv_val, 0 );
1180                         backsql_PrintErrors( bi->sql_db_env, dbh, 
1181                                 sth, rc );
1182                         SQLFreeStmt( sth, SQL_DROP );
1183
1184                         rs->sr_text = "SQL-backend error";
1185                         rs->sr_err = LDAP_OTHER;
1186                         e = NULL;
1187                         goto done;
1188                 }
1189                 colnum++;
1190         }
1191
1192         if ( oc->bom_create_hint ) {
1193                 at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint );
1194                 if ( at && at->a_vals ) {
1195                         backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
1196                                         at->a_vals[0].bv_val,
1197                                         at->a_vals[0].bv_len );
1198                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1199                                         "create_proc hint: param = '%s'\n",
1200                                         at->a_vals[0].bv_val, 0, 0 );
1201
1202                 } else {
1203                         backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
1204                                         "", 0 );
1205                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1206                                         "create_proc hint (%s) not avalable\n",
1207                                         oc->bom_create_hint->ad_cname.bv_val,
1208                                         0, 0 );
1209                 }
1210                 colnum++;
1211         }
1212
1213         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): executing \"%s\"\n",
1214                 op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 );
1215         rc = SQLExecute( sth );
1216         if ( rc != SQL_SUCCESS ) {
1217                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1218                         "create_proc execution failed\n",
1219                         op->ora_e->e_name.bv_val, 0, 0 );
1220                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1221                 SQLFreeStmt( sth, SQL_DROP );
1222                 rs->sr_err = LDAP_OTHER;
1223                 rs->sr_text = "SQL-backend error";
1224                 e = NULL;
1225                 goto done;
1226         }
1227
1228         /* FIXME: after SQLExecute(), the row is already inserted
1229          * (at least with PostgreSQL and unixODBC); needs investigation */
1230
1231         if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1232                 SWORD           ncols;
1233                 SQLINTEGER      value_len;
1234
1235                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1236                         SQLFreeStmt( sth, SQL_DROP );
1237
1238                         rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 );
1239                         if ( rc != SQL_SUCCESS ) {
1240                                 rs->sr_err = LDAP_OTHER;
1241                                 rs->sr_text = "SQL-backend error";
1242                                 e = NULL;
1243                                 goto done;
1244                         }
1245
1246                         rc = SQLExecute( sth );
1247                         if ( rc != SQL_SUCCESS ) {
1248                                 rs->sr_err = LDAP_OTHER;
1249                                 rs->sr_text = "SQL-backend error";
1250                                 e = NULL;
1251                                 goto done;
1252                         }
1253                 }
1254
1255                 /*
1256                  * the query to know the id of the inserted entry
1257                  * must be embedded in the create procedure
1258                  */
1259                 rc = SQLNumResultCols( sth, &ncols );
1260                 if ( rc != SQL_SUCCESS ) {
1261                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1262                                 "create_proc result evaluation failed\n",
1263                                 op->ora_e->e_name.bv_val, 0, 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                 } else if ( ncols != 1 ) {
1272                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1273                                 "create_proc result is bogus (ncols=%d)\n",
1274                                 op->ora_e->e_name.bv_val, ncols, 0 );
1275                         backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1276                         SQLFreeStmt( sth, SQL_DROP );
1277                         rs->sr_err = LDAP_OTHER;
1278                         rs->sr_text = "SQL-backend error";
1279                         e = NULL;
1280                         goto done;
1281                 }
1282
1283 #if 0
1284                 {
1285                         SQLCHAR         colname[ 64 ];
1286                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
1287                         UDWORD          col_prec;
1288
1289                         /*
1290                          * FIXME: check whether col_type is compatible,
1291                          * if it can be null and so on ...
1292                          */
1293                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
1294                                         &colname[ 0 ], 
1295                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
1296                                         &name_len, &col_type,
1297                                         &col_prec, &col_scale, &col_null );
1298                 }
1299 #endif
1300
1301                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1302                                 (SQLPOINTER)&new_keyval, 
1303                                 (SQLINTEGER)sizeof( new_keyval ), 
1304                                 &value_len );
1305
1306                 rc = SQLFetch( sth );
1307
1308                 if ( value_len <= 0 ) {
1309                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1310                                 "create_proc result is empty?\n",
1311                                 op->ora_e->e_name.bv_val, 0, 0 );
1312                         backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1313                         SQLFreeStmt( sth, SQL_DROP );
1314                         rs->sr_err = LDAP_OTHER;
1315                         rs->sr_text = "SQL-backend error";
1316                         e = NULL;
1317                         goto done;
1318                 }
1319         }
1320
1321         SQLFreeStmt( sth, SQL_DROP );
1322
1323         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1324                 "create_proc returned keyval=%ld\n",
1325                 op->ora_e->e_name.bv_val, new_keyval, 0 );
1326
1327         rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 );
1328         if ( rc != SQL_SUCCESS ) {
1329                 rs->sr_err = LDAP_OTHER;
1330                 rs->sr_text = "SQL-backend error";
1331                 e = NULL;
1332                 goto done;
1333         }
1334         
1335         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn );
1336         if ( rc != SQL_SUCCESS ) {
1337                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1338                         "error binding DN parameter for objectClass %s\n",
1339                         op->ora_e->e_name.bv_val,
1340                         oc->bom_oc->soc_cname.bv_val, 0 );
1341                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1342                         sth, rc );
1343                 SQLFreeStmt( sth, SQL_DROP );
1344
1345                 rs->sr_text = "SQL-backend error";
1346                 rs->sr_err = LDAP_OTHER;
1347                 e = NULL;
1348                 goto done;
1349         }
1350
1351         rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id );
1352         if ( rc != SQL_SUCCESS ) {
1353                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1354                         "error binding objectClass ID parameter "
1355                         "for objectClass %s\n",
1356                         op->ora_e->e_name.bv_val,
1357                         oc->bom_oc->soc_cname.bv_val, 0 );
1358                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1359                         sth, rc );
1360                 SQLFreeStmt( sth, SQL_DROP );
1361
1362                 rs->sr_text = "SQL-backend error";
1363                 rs->sr_err = LDAP_OTHER;
1364                 e = NULL;
1365                 goto done;
1366         }
1367
1368         rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id );
1369         if ( rc != SQL_SUCCESS ) {
1370                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1371                         "error binding parent ID parameter "
1372                         "for objectClass %s\n",
1373                         op->ora_e->e_name.bv_val,
1374                         oc->bom_oc->soc_cname.bv_val, 0 );
1375                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1376                         sth, rc );
1377                 SQLFreeStmt( sth, SQL_DROP );
1378
1379                 rs->sr_text = "SQL-backend error";
1380                 rs->sr_err = LDAP_OTHER;
1381                 e = NULL;
1382                 goto done;
1383         }
1384
1385         rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval );
1386         if ( rc != SQL_SUCCESS ) {
1387                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1388                         "error binding entry ID parameter "
1389                         "for objectClass %s\n",
1390                         op->ora_e->e_name.bv_val,
1391                         oc->bom_oc->soc_cname.bv_val, 0 );
1392                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1393                         sth, rc );
1394                 SQLFreeStmt( sth, SQL_DROP );
1395
1396                 rs->sr_text = "SQL-backend error";
1397                 rs->sr_err = LDAP_OTHER;
1398                 e = NULL;
1399                 goto done;
1400         }
1401
1402         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\" for dn \"%s\"\n",
1403                         bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 0 );
1404 #ifdef BACKSQL_ARBITRARY_KEY
1405         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1406                         "p_id=%s, keyval=%ld\n",
1407                         oc->bom_id, bsi.bsi_base_id.eid_id.bv_val, new_keyval );
1408 #else /* ! BACKSQL_ARBITRARY_KEY */
1409         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1410                         "p_id=%ld, keyval=%ld\n",
1411                         oc->bom_id, bsi.bsi_base_id.eid_id, new_keyval );
1412 #endif /* ! BACKSQL_ARBITRARY_KEY */
1413         rc = SQLExecute( sth );
1414         if ( rc != SQL_SUCCESS ) {
1415                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1416                         "could not insert ldap_entries record\n",
1417                         op->ora_e->e_name.bv_val, 0, 0 );
1418                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
1419                 
1420                 /*
1421                  * execute delete_proc to delete data added !!!
1422                  */
1423                 SQLFreeStmt( sth, SQL_DROP );
1424                 rs->sr_err = LDAP_OTHER;
1425                 rs->sr_text = "SQL-backend error";
1426                 e = NULL;
1427                 goto done;
1428         }
1429
1430         SQLFreeStmt( sth, SQL_DROP );
1431
1432         for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
1433                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
1434                         "adding attribute \"%s\"\n", 
1435                         at->a_desc->ad_cname.bv_val, 0, 0 );
1436
1437                 /*
1438                  * Skip:
1439                  * - the first occurrence of objectClass, which is used
1440                  *   to determine how to build the SQL entry (FIXME ?!?)
1441                  * - operational attributes
1442                  * - empty attributes (FIXME ?!?)
1443                  */
1444                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1445                         continue;
1446                 }
1447
1448                 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1449                         at_objectClass = at;
1450                         continue;
1451                 }
1452
1453                 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
1454                 if ( rs->sr_err != LDAP_SUCCESS ) {
1455                         e = op->ora_e;
1456                         goto done;
1457                 }
1458         }
1459
1460         if ( at_objectClass ) {
1461                 rs->sr_err = backsql_add_attr( op, rs, dbh, oc,
1462                                 at_objectClass, new_keyval );
1463                 if ( rs->sr_err != LDAP_SUCCESS ) {
1464                         e = op->ora_e;
1465                         goto done;
1466                 }
1467         }
1468
1469 done:;
1470         /*
1471          * Commit only if all operations succeed
1472          */
1473         if ( sth != SQL_NULL_HSTMT ) {
1474                 SQLUSMALLINT    CompletionType = SQL_ROLLBACK;
1475
1476                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
1477                         assert( e == NULL );
1478                         CompletionType = SQL_COMMIT;
1479                 }
1480
1481                 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
1482         }
1483
1484         /*
1485          * FIXME: NOOP does not work for add -- it works for all 
1486          * the other operations, and I don't get the reason :(
1487          * 
1488          * hint: there might be some autocommit in Postgres
1489          * so that when the unique id of the key table is
1490          * automatically increased, there's no rollback.
1491          * We might implement a "rollback" procedure consisting
1492          * in deleting that row.
1493          */
1494
1495         if ( e != NULL ) {
1496                 int     disclose = 1;
1497
1498                 if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
1499                         /* mask already collected */
1500                         disclose = 0;
1501
1502                 } else if ( e == &p && !access_allowed( op, &p,
1503                                         slap_schema.si_ad_entry, NULL,
1504                                         ACL_DISCLOSE, NULL ) )
1505                 {
1506                         disclose = 0;
1507                 }
1508
1509                 if ( disclose == 0 ) {
1510                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
1511                         rs->sr_text = NULL;
1512                         rs->sr_matched = NULL;
1513                         if ( rs->sr_ref ) {
1514                                 ber_bvarray_free( rs->sr_ref );
1515                                 rs->sr_ref = NULL;
1516                         }
1517                 }
1518         }
1519
1520         if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
1521                 rs->sr_err = LDAP_X_NO_OPERATION;
1522         }
1523
1524         send_ldap_result( op, rs );
1525         slap_graduate_commit_csn( op );
1526
1527         if ( !BER_BVISNULL( &realdn )
1528                         && realdn.bv_val != op->ora_e->e_name.bv_val )
1529         {
1530                 ch_free( realdn.bv_val );
1531         }
1532
1533         if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
1534                 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
1535         }
1536
1537         if ( !BER_BVISNULL( &p.e_nname ) ) {
1538                 backsql_entry_clean( op, &p );
1539         }
1540
1541         Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1542                         op->ora_e->e_name.bv_val,
1543                         rs->sr_err,
1544                         rs->sr_text ? rs->sr_text : "" );
1545
1546         rs->sr_text = NULL;
1547         rs->sr_matched = NULL;
1548         if ( rs->sr_ref ) {
1549                 ber_bvarray_free( rs->sr_ref );
1550                 rs->sr_ref = NULL;
1551         }
1552
1553         return rs->sr_err;
1554 }
1555