]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/add.c
Revert ITS#3353 patch, it needs to be reworked.
[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->sql_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->sql_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->sql_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->sql_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->sql_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->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 #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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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->sql_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 ( dn_match( 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->sql_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->sql_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->sql_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->sql_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                                 realndn = BER_BVNULL,
886                                 realpdn = BER_BVNULL;
887
888         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
889                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
890
891         /* check schema */
892         if ( global_schemacheck ) {
893                 char            textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
894
895                 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
896                                 NULL,
897                                 &rs->sr_text, textbuf, sizeof( textbuf ) );
898                 if ( rs->sr_err != LDAP_SUCCESS ) {
899                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
900                                 "entry failed schema check -- aborting\n",
901                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
902                         goto done;
903                 }
904         }
905
906         /* search structural objectClass */
907         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
908                 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
909                         break;
910                 }
911         }
912
913         /* there must exist */
914         assert( at != NULL );
915
916         /* I guess we should play with sub/supertypes to find a suitable oc */
917         oc = backsql_name2oc( bi, &at->a_vals[0] );
918
919         if ( oc == NULL ) {
920                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
921                         "cannot map structuralObjectClass \"%s\" -- aborting\n",
922                         op->oq_add.rs_e->e_name.bv_val,
923                         at->a_vals[0].bv_val, 0 );
924                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
925                 rs->sr_text = "operation not permitted within namingContext";
926                 goto done;
927         }
928
929         if ( oc->bom_create_proc == NULL ) {
930                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
931                         "create procedure is not defined "
932                         "for structuralObjectClass \"%s\" - aborting\n",
933                         op->oq_add.rs_e->e_name.bv_val,
934                         at->a_vals[0].bv_val, 0 );
935                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
936                 rs->sr_text = "operation not permitted within namingContext";
937                 goto done;
938
939         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
940                         && oc->bom_create_keyval == NULL ) {
941                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
942                         "create procedure needs select procedure, "
943                         "but none is defined for structuralObjectClass \"%s\" "
944                         "- aborting\n",
945                         op->oq_add.rs_e->e_name.bv_val,
946                         at->a_vals[0].bv_val, 0 );
947                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
948                 rs->sr_text = "operation not permitted within namingContext";
949                 goto done;
950         }
951
952         rs->sr_err = backsql_get_db_conn( op, &dbh );
953         if ( rs->sr_err != LDAP_SUCCESS ) {
954                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
955                         "could not get connection handle - exiting\n", 
956                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
957                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
958                         ?  "SQL-backend error" : NULL;
959                 goto done;
960         }
961
962         /*
963          * Check if entry exists
964          */
965         realdn = op->oq_add.rs_e->e_name;
966         if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
967                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
968                         "backsql_api_dn2odbc(\"%s\") failed\n", 
969                         op->oq_add.rs_e->e_name.bv_val, realdn.bv_val, 0 );
970                 rs->sr_err = LDAP_OTHER;
971                 rs->sr_text = "SQL-backend error";
972                 goto done;
973         }
974
975         realndn = op->oq_add.rs_e->e_nname;
976         if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
977                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
978                         "backsql_api_dn2odbc(\"%s\") failed\n", 
979                         op->oq_add.rs_e->e_name.bv_val, realndn.bv_val, 0 );
980                 rs->sr_err = LDAP_OTHER;
981                 rs->sr_text = "SQL-backend error";
982                 goto done;
983         }
984
985         rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realndn );
986         if ( rs->sr_err == LDAP_SUCCESS ) {
987                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
988                         "entry exists\n",
989                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
990                 rs->sr_err = LDAP_ALREADY_EXISTS;
991                 goto done;
992         }
993
994         /*
995          * Get the parent dn and see if the corresponding entry exists.
996          */
997         if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
998                 pdn = slap_empty_bv;
999
1000         } else {
1001                 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
1002         }
1003
1004         realpdn = pdn;
1005         if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
1006                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1007                         "backsql_api_dn2odbc(\"%s\") failed\n", 
1008                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
1009                 rs->sr_err = LDAP_OTHER;
1010                 rs->sr_text = "SQL-backend error";
1011                 goto done;
1012         }
1013
1014         rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
1015         if ( rs->sr_err != LDAP_SUCCESS ) {
1016                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1017                         "could not lookup parent entry for new record \"%s\"\n",
1018                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
1019
1020                 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
1021                         goto done;
1022                 }
1023
1024                 /*
1025                  * no parent!
1026                  *  if not attempting to add entry at suffix or with parent ""
1027                  */
1028                 if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
1029                         || !BER_BVISEMPTY( &pdn ) ) && !is_entry_glue( op->oq_add.rs_e )
1030                         && !BACKSQL_ALLOW_ORPHANS( bi ) )
1031                 {
1032                         Debug( LDAP_DEBUG_TRACE, "   backsql_add: %s denied\n",
1033                                 BER_BVISEMPTY( &pdn ) ? "suffix" : "entry at root",
1034                                 0, 0 );
1035                         /*
1036                          * Look for matched
1037                          */
1038                         while ( 1 ) {
1039                                 struct berval   dn;
1040                                 char            *matched = NULL;
1041         
1042                                 if ( realpdn.bv_val != pdn.bv_val ) {
1043                                         ch_free( realpdn.bv_val );
1044                                 }
1045         
1046                                 dn = pdn;
1047                                 dnParent( &dn, &pdn );
1048         
1049                                 /*
1050                                  * Empty DN ("") defaults to LDAP_SUCCESS
1051                                  */
1052                                 realpdn = pdn;
1053                                 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
1054                                         Debug( LDAP_DEBUG_TRACE,
1055                                                 "   backsql_add(\"%s\"): "
1056                                                 "backsql_api_dn2odbc failed\n", 
1057                                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1058                                         rs->sr_err = LDAP_OTHER;
1059                                         rs->sr_text = "SQL-backend error";
1060                                         goto done;
1061                                 }
1062         
1063                                 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
1064                                 switch ( rs->sr_err ) {
1065                                 case LDAP_NO_SUCH_OBJECT:
1066                                         if ( !BER_BVISEMPTY( &pdn ) ) {
1067                                                 break;
1068                                         }
1069                                         /* fail over to next case */
1070                                         
1071                                 case LDAP_SUCCESS:
1072                                         matched = pdn.bv_val;
1073                                         /* fail over to next case */
1074         
1075                                 default:
1076                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
1077                                         rs->sr_matched = matched;
1078                                         goto done;
1079                                 } 
1080                         }
1081                 } else {
1082
1083 #ifdef BACKSQL_ARBITRARY_KEY
1084                         ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
1085 #else /* ! BACKSQL_ARBITRARY_KEY */
1086                         parent_id.eid_id = 0;
1087 #endif /* ! BACKSQL_ARBITRARY_KEY */
1088                         rs->sr_err = LDAP_SUCCESS;
1089                 }
1090         }
1091
1092         /* check "children" pseudo-attribute access to parent */
1093         p.e_attrs = NULL;
1094         p.e_name = pdn;
1095         dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
1096         if ( !access_allowed( op, &p, slap_schema.si_ad_children,
1097                                 NULL, ACL_WRITE, NULL ) ) {
1098                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1099                 goto done;
1100         }
1101
1102         /*
1103          * create_proc is executed; if expect_return is set, then
1104          * an output parameter is bound, which should contain 
1105          * the id of the added row; otherwise the procedure
1106          * is expected to return the id as the first column of a select
1107          */
1108
1109         rc = SQLAllocStmt( dbh, &sth );
1110         if ( rc != SQL_SUCCESS ) {
1111                 rs->sr_err = LDAP_OTHER;
1112                 rs->sr_text = "SQL-backend error";
1113                 goto done;
1114         }
1115
1116         if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1117                 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval );
1118                 if ( rc != SQL_SUCCESS ) {
1119                         Debug( LDAP_DEBUG_TRACE,
1120                                 "   backsql_add_attr(): "
1121                                 "error binding keyval parameter for objectClass %s\n",
1122                                 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1123                         backsql_PrintErrors( bi->sql_db_env, dbh, 
1124                                 sth, rc );
1125                         SQLFreeStmt( sth, SQL_DROP );
1126
1127                         rs->sr_text = "SQL-backend error";
1128                         rs->sr_err = LDAP_OTHER;
1129                         goto done;
1130                 }
1131         }
1132
1133         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): executing \"%s\"\n",
1134                 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
1135         rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
1136         if ( rc != SQL_SUCCESS ) {
1137                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1138                         "create_proc execution failed\n",
1139                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1140                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1141                 SQLFreeStmt( sth, SQL_DROP );
1142                 rs->sr_err = LDAP_OTHER;
1143                 rs->sr_text = "SQL-backend error";
1144                 goto done;
1145         }
1146
1147         if ( op->o_noop ) {
1148                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1149         }
1150
1151         if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
1152                 SWORD           ncols;
1153                 SQLINTEGER      value_len;
1154
1155                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1156                         SQLFreeStmt( sth, SQL_DROP );
1157                         rc = SQLAllocStmt( dbh, &sth );
1158                         if ( rc != SQL_SUCCESS ) {
1159                                 rs->sr_err = LDAP_OTHER;
1160                                 rs->sr_text = "SQL-backend error";
1161                                 goto done;
1162                         }
1163
1164                         rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
1165                         if ( rc != SQL_SUCCESS ) {
1166                                 rs->sr_err = LDAP_OTHER;
1167                                 rs->sr_text = "SQL-backend error";
1168                                 goto done;
1169                         }
1170                 }
1171
1172                 /*
1173                  * the query to know the id of the inserted entry
1174                  * must be embedded in the create procedure
1175                  */
1176                 rc = SQLNumResultCols( sth, &ncols );
1177                 if ( rc != SQL_SUCCESS ) {
1178                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1179                                 "create_proc result evaluation failed\n",
1180                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1181                         backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1182                         SQLFreeStmt( sth, SQL_DROP );
1183                         rs->sr_err = LDAP_OTHER;
1184                         rs->sr_text = "SQL-backend error";
1185                         goto done;
1186
1187                 } else if ( ncols != 1 ) {
1188                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1189                                 "create_proc result is bogus (ncols=%d)\n",
1190                                 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
1191                         backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1192                         SQLFreeStmt( sth, SQL_DROP );
1193                         rs->sr_err = LDAP_OTHER;
1194                         rs->sr_text = "SQL-backend error";
1195                         goto done;
1196                 }
1197
1198 #if 0
1199                 {
1200                         SQLCHAR         colname[ 64 ];
1201                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
1202                         UDWORD          col_prec;
1203
1204                         /*
1205                          * FIXME: check whether col_type is compatible,
1206                          * if it can be null and so on ...
1207                          */
1208                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
1209                                         &colname[ 0 ], 
1210                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
1211                                         &name_len, &col_type,
1212                                         &col_prec, &col_scale, &col_null );
1213                 }
1214 #endif
1215
1216                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1217                                 (SQLPOINTER)&new_keyval, 
1218                                 (SQLINTEGER)sizeof( new_keyval ), 
1219                                 &value_len );
1220
1221                 rc = SQLFetch( sth );
1222
1223                 if ( value_len <= 0 ) {
1224                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1225                                 "create_proc result is empty?\n",
1226                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1227                         backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
1228                         SQLFreeStmt( sth, SQL_DROP );
1229                         rs->sr_err = LDAP_OTHER;
1230                         rs->sr_text = "SQL-backend error";
1231                         goto done;
1232                 }
1233         }
1234
1235         SQLFreeStmt( sth, SQL_DROP );
1236
1237         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1238                 "create_proc returned keyval=%ld\n",
1239                 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
1240
1241         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
1242                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
1243                         "adding attribute \"%s\"\n", 
1244                         at->a_desc->ad_cname.bv_val, 0, 0 );
1245
1246                 /*
1247                  * Skip:
1248                  * - the first occurrence of objectClass, which is used
1249                  *   to determine how to build the SQL entry (FIXME ?!?)
1250                  * - operational attributes
1251                  * - empty attributes (FIXME ?!?)
1252                  */
1253                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1254                         continue;
1255                 }
1256
1257                 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1258                         at_objectClass = at;
1259                         continue;
1260                 }
1261
1262                 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
1263                 if ( rs->sr_err != LDAP_SUCCESS ) {
1264                         goto done;
1265                 }
1266         }
1267
1268         rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_query, 0 );
1269         if ( rc != SQL_SUCCESS ) {
1270                 rs->sr_err = LDAP_OTHER;
1271                 rs->sr_text = "SQL-backend error";
1272                 goto done;
1273         }
1274         
1275         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn );
1276         if ( rc != SQL_SUCCESS ) {
1277                 Debug( LDAP_DEBUG_TRACE,
1278                         "   backsql_add_attr(): "
1279                         "error binding DN parameter for objectClass %s\n",
1280                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
1281                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1282                         sth, rc );
1283                 SQLFreeStmt( sth, SQL_DROP );
1284
1285                 rs->sr_text = "SQL-backend error";
1286                 rs->sr_err = LDAP_OTHER;
1287                 goto done;
1288         }
1289
1290         rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id );
1291         if ( rc != SQL_SUCCESS ) {
1292                 Debug( LDAP_DEBUG_TRACE,
1293                         "   backsql_add_attr(): "
1294                         "error binding objectClass ID parameter for objectClass %s\n",
1295                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
1296                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1297                         sth, rc );
1298                 SQLFreeStmt( sth, SQL_DROP );
1299
1300                 rs->sr_text = "SQL-backend error";
1301                 rs->sr_err = LDAP_OTHER;
1302                 goto done;
1303         }
1304
1305         rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &parent_id.eid_id );
1306         if ( rc != SQL_SUCCESS ) {
1307                 Debug( LDAP_DEBUG_TRACE,
1308                         "   backsql_add_attr(): "
1309                         "error binding parent ID parameter for objectClass %s\n",
1310                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
1311                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1312                         sth, rc );
1313                 SQLFreeStmt( sth, SQL_DROP );
1314
1315                 rs->sr_text = "SQL-backend error";
1316                 rs->sr_err = LDAP_OTHER;
1317                 goto done;
1318         }
1319
1320         rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval );
1321         if ( rc != SQL_SUCCESS ) {
1322                 Debug( LDAP_DEBUG_TRACE,
1323                         "   backsql_add_attr(): "
1324                         "error binding entry ID parameter for objectClass %s\n",
1325                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
1326                 backsql_PrintErrors( bi->sql_db_env, dbh, 
1327                         sth, rc );
1328                 SQLFreeStmt( sth, SQL_DROP );
1329
1330                 rs->sr_text = "SQL-backend error";
1331                 rs->sr_err = LDAP_OTHER;
1332                 goto done;
1333         }
1334
1335         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\" for dn \"%s\"\n",
1336                         bi->sql_insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1337 #ifdef BACKSQL_ARBITRARY_KEY
1338         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1339                         "parent_id=%s, keyval=%ld\n",
1340                         oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1341 #else /* ! BACKSQL_ARBITRARY_KEY */
1342         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1343                         "parent_id=%ld, keyval=%ld\n",
1344                         oc->bom_id, parent_id.eid_id, new_keyval );
1345 #endif /* ! BACKSQL_ARBITRARY_KEY */
1346         rc = SQLExecute( sth );
1347         if ( rc != SQL_SUCCESS ) {
1348                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1349                         "could not insert ldap_entries record\n",
1350                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1351                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
1352                 
1353                 /*
1354                  * execute delete_proc to delete data added !!!
1355                  */
1356                 SQLFreeStmt( sth, SQL_DROP );
1357                 rs->sr_err = LDAP_OTHER;
1358                 rs->sr_text = "SQL-backend error";
1359                 goto done;
1360         }
1361
1362         /* FIXME: need ldap_entries.id of newly added entry */
1363         if ( at_objectClass ) {
1364                 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at_objectClass, new_keyval );
1365                 if ( rs->sr_err != LDAP_SUCCESS ) {
1366                         goto done;
1367                 }
1368         }
1369
1370         SQLFreeStmt( sth, SQL_DROP );
1371
1372 done:;
1373         /*
1374          * Commit only if all operations succeed
1375          */
1376         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
1377                 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1378
1379         } else {
1380                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
1381         }
1382
1383         /*
1384          * FIXME: NOOP does not work for add -- it works for all 
1385          * the other operations, and I don't get the reason :(
1386          * 
1387          * hint: there might be some autocommit in Postgres
1388          * so that when the unique id of the key table is
1389          * automatically increased, there's no rollback.
1390          * We might implement a "rollback" procedure consisting
1391          * in deleting that row.
1392          */
1393
1394         send_ldap_result( op, rs );
1395
1396         if ( !BER_BVISNULL( &realdn )
1397                         && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
1398         {
1399                 ch_free( realdn.bv_val );
1400         }
1401         if ( !BER_BVISNULL( &realndn )
1402                         && realndn.bv_val != op->oq_add.rs_e->e_nname.bv_val )
1403         {
1404                 ch_free( realndn.bv_val );
1405         }
1406         if ( !BER_BVISNULL( &realpdn ) && realpdn.bv_val != pdn.bv_val ) {
1407                 ch_free( realpdn.bv_val );
1408         }
1409         if ( !BER_BVISNULL( &parent_id.eid_ndn ) ) {
1410                 (void)backsql_free_entryID( &parent_id, 0 );
1411         }
1412
1413         Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1414                         op->oq_add.rs_e->e_name.bv_val,
1415                         rs->sr_err,
1416                         rs->sr_text ? rs->sr_text : "" );
1417
1418         return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1419 }
1420
1421 #endif /* SLAPD_SQL */
1422