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