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