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