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