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