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