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