]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/modify.c
2757d33e4c4b660279d67a73c43bbd2fa7c1912e
[openldap] / servers / slapd / back-sql / modify.c
1 /*
2  *       Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
3  *
4  *       Redistribution and use in source and binary forms are permitted only
5  *       as authorized by the OpenLDAP Public License.  A copy of this
6  *       license is available at http://www.OpenLDAP.org/license.html or
7  *       in file LICENSE in the top-level directory of the distribution.
8  */
9
10 #include "portable.h"
11
12 #ifdef SLAPD_SQL
13
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <string.h>
17 #include "slap.h"
18 #include "ldap_pvt.h"
19 #include "back-sql.h"
20 #include "sql-wrap.h"
21 #include "schema-map.h"
22 #include "entry-id.h"
23 #include "util.h"
24
25 /*
26  * PostgreSQL doesn't work without :(
27  */
28 #define BACKSQL_REALLOC_STMT
29
30 static int
31 backsql_modify_internal(
32         backsql_info            *bi,
33         SQLHDBC                 dbh, 
34         backsql_oc_map_rec      *oc,
35         backsql_entryID         *e_id,
36         Modifications           *modlist )
37 {
38         RETCODE         rc;
39         SQLHSTMT        sth;
40         Modifications   *ml;
41
42         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
43                 "traversing modifications list\n", 0, 0, 0 );
44 #ifndef BACKSQL_REALLOC_STMT
45         SQLAllocStmt( dbh, &sth );
46 #endif /* BACKSQL_REALLOC_STMT */
47         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
48                 AttributeDescription *ad;
49                 backsql_at_map_rec      *at = NULL;
50                 struct berval           *at_val;
51                 Modification            *c_mod;
52                 int                     i;
53                 /* first parameter no, parameter order */
54                 SQLUSMALLINT            pno, po;
55                 /* procedure return code */
56                 int                     prc;
57
58 #ifdef BACKSQL_REALLOC_STMT
59                 SQLAllocStmt( dbh, &sth );
60 #endif /* BACKSQL_REALLOC_STMT */
61
62                 c_mod = &ml->sml_mod;
63
64                 ad = c_mod->sm_desc;
65                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): attribute '%s'\n",
66                                 ad->ad_cname.bv_val, 0, 0 );
67                 at = backsql_ad2at( oc, ad );
68                 if ( at == NULL ) {
69                         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
70                                 "attribute provided is not registered "
71                                 "in objectclass '%s'\n",
72                                 ad->ad_cname.bv_val, 0, 0 );
73                         continue;
74                 }
75   
76                 switch( c_mod->sm_op ) {
77                 case LDAP_MOD_REPLACE: {
78                         SQLHSTMT asth;
79                         BACKSQL_ROW_NTS row;
80                          
81                         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
82                                 "replacing values for attribute '%s'\n",
83                                 at->name.bv_val, 0, 0 );
84
85                         if ( at->add_proc == NULL ) {
86                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
87                                         "add procedure is not defined "
88                                         "for attribute '%s' "
89                                         "- unable to perform replacements\n",
90                                         at->name.bv_val, 0, 0 );
91                                 break;
92                         }
93
94                         if ( at->delete_proc == NULL ) {
95                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
96                                         "delete procedure is not defined "
97                                         "for attribute '%s' "
98                                         "- adding only\n",
99                                         at->name.bv_val, 0, 0 );
100                                 goto add_only;
101                         }
102                         
103 del_all:
104                         rc = backsql_Prepare( dbh, &asth, at->query, 0 );
105                         if ( rc != SQL_SUCCESS ) {
106                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
107                                         "error preparing query\n", 0, 0, 0 );
108                                 backsql_PrintErrors( bi->db_env, dbh, 
109                                                 asth, rc );
110                                 break;
111                         }
112
113                         rc = backsql_BindParamID( asth, 1, &e_id->keyval );
114                         if ( rc != SQL_SUCCESS ) {
115                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
116                                         "error binding key value parameter\n",
117                                         0, 0, 0 );
118                                 backsql_PrintErrors( bi->db_env, dbh, 
119                                                 asth, rc );
120                                 SQLFreeStmt( asth, SQL_DROP );
121                                 break;
122                         }
123                         
124                         rc = SQLExecute( asth );
125                         if ( !BACKSQL_SUCCESS( rc ) ) {
126                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
127                                         "error executing attribute query\n",
128                                         0, 0, 0 );
129                                 backsql_PrintErrors( bi->db_env, dbh, 
130                                                 asth, rc );
131                                 SQLFreeStmt( asth, SQL_DROP );
132                                 break;
133                         }
134
135                         backsql_BindRowAsStrings( asth, &row );
136                         rc = SQLFetch( asth );
137                         for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
138                                 for ( i = 0; i < row.ncols; i++ ) {
139                                         if ( BACKSQL_IS_DEL( at->expect_return ) ) {
140                                                 pno = 1;
141                                                 SQLBindParameter(sth, 1,
142                                                         SQL_PARAM_OUTPUT,
143                                                         SQL_C_ULONG,
144                                                         SQL_INTEGER,
145                                                         0, 0, &prc, 0, 0 );
146                                         } else {
147                                                 pno = 0;
148                                         }
149                                         po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
150                                         SQLBindParameter( sth, pno + 1 + po,
151                                                 SQL_PARAM_INPUT,
152                                                 SQL_C_ULONG, SQL_INTEGER,
153                                                 0, 0, &e_id->keyval, 0, 0 );
154
155                                         /*
156                                          * check for syntax needed here 
157                                          * maybe need binary bind?
158                                          */
159                                         SQLBindParameter(sth, pno + 2 - po,
160                                                 SQL_PARAM_INPUT,
161                                                 SQL_C_CHAR, SQL_CHAR,
162                                                 0, 0, row.cols[ i ],
163                                                 strlen( row.cols[ i ] ), 0 );
164                          
165                                         Debug( LDAP_DEBUG_TRACE, 
166                                                 "backsql_modify(): "
167                                                 "executing '%s'\n",
168                                                 at->delete_proc, 0, 0 );
169                                         rc = SQLExecDirect( sth,
170                                                 at->delete_proc, SQL_NTS );
171                                         if ( rc != SQL_SUCCESS ) {
172                                                 Debug( LDAP_DEBUG_TRACE,
173                                                         "backsql_modify(): "
174                                                         "delete_proc "
175                                                         "execution failed\n",
176                                                         0, 0, 0 );
177                                                 backsql_PrintErrors( bi->db_env,
178                                                                 dbh, sth, rc );
179                                         }
180 #ifdef BACKSQL_REALLOC_STMT
181                                         SQLFreeStmt( sth, SQL_DROP );
182                                         SQLAllocStmt( dbh, &sth );
183 #endif /* BACKSQL_REALLOC_STMT */
184                                 }
185                         }
186                         backsql_FreeRow( &row );
187                         SQLFreeStmt( asth, SQL_DROP );
188                 }
189                                        
190                 /*
191                  * PASSTHROUGH - to add new attributes -- do NOT add break
192                  */
193                 case LDAP_MOD_ADD:
194                 case SLAP_MOD_SOFTADD:
195 add_only:;
196                         if ( at->add_proc == NULL ) {
197                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
198                                         "add procedure is not defined "
199                                         "for attribute '%s'\n",
200                                         at->name.bv_val, 0, 0 );
201                                 break;
202                         }
203                         
204                         if ( c_mod->sm_bvalues == NULL ) {
205                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
206                                         "no values given to add "
207                                         "for attribute '%s'\n",
208                                         at->name.bv_val, 0, 0 );
209                                 break;
210                         }
211                         
212                         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
213                                 "adding new values for attribute '%s'\n",
214                                 at->name.bv_val, 0, 0 );
215                         for ( i = 0, at_val = c_mod->sm_bvalues;
216                                         at_val->bv_val != NULL; 
217                                         i++, at_val++ ) {
218                                 if ( BACKSQL_IS_ADD( at->expect_return ) ) {
219                                         pno = 1;
220                                         SQLBindParameter( sth, 1,
221                                                 SQL_PARAM_OUTPUT,
222                                                 SQL_C_ULONG, SQL_INTEGER,
223                                                 0, 0, &prc, 0, 0);
224                                 } else {
225                                         pno = 0;
226                                 }
227                                 po = ( BACKSQL_IS_ADD( at->param_order ) ) > 0;
228                                 SQLBindParameter( sth, pno + 1 + po,
229                                         SQL_PARAM_INPUT, 
230                                         SQL_C_ULONG, SQL_INTEGER,
231                                         0, 0, &e_id->keyval, 0, 0 );
232
233                                 /*
234                                  * check for syntax needed here
235                                  * maybe need binary bind?
236                                  */
237                                 SQLBindParameter( sth, pno + 2 - po,
238                                         SQL_PARAM_INPUT,
239                                         SQL_C_CHAR, SQL_CHAR,
240                                         0, 0, at_val->bv_val, 
241                                         at_val->bv_len, 0 );
242
243                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
244                                         "executing '%s'\n", 
245                                         at->add_proc, 0, 0 );
246                                 rc = SQLExecDirect( sth, at->add_proc, 
247                                                 SQL_NTS );
248                                 if ( rc != SQL_SUCCESS ) {
249                                         Debug( LDAP_DEBUG_TRACE,
250                                                 "backsql_modify(): "
251                                                 "add_proc execution failed\n",
252                                                 0, 0, 0 );
253                                         backsql_PrintErrors( bi->db_env,
254                                                         dbh, sth, rc );
255                                 }
256 #ifdef BACKSQL_REALLOC_STMT
257                                 SQLFreeStmt( sth, SQL_DROP );
258                                 SQLAllocStmt( dbh, &sth );
259 #endif /* BACKSQL_REALLOC_STMT */
260                         }
261                         break;
262                         
263                 case LDAP_MOD_DELETE:
264                         if ( at->delete_proc == NULL ) {
265                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
266                                         "delete procedure is not defined "
267                                         "for attribute '%s'\n",
268                                         at->name.bv_val, 0, 0 );
269                                 break;
270                         }
271
272                         if ( c_mod->sm_bvalues == NULL ) {
273                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
274                                         "no values given to delete "
275                                         "for attribute '%s' "
276                                         "-- deleting all values\n",
277                                         at->name.bv_val, 0, 0 );
278                                 goto del_all;
279                         }
280
281                         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
282                                 "deleting values for attribute '%s'\n",
283                                 at->name.bv_val, 0, 0 );
284                         for ( i = 0, at_val = c_mod->sm_bvalues;
285                                         at_val->bv_val != NULL;
286                                         i++, at_val++ ) {
287                                 if ( BACKSQL_IS_DEL( at->expect_return ) ) {
288                                         pno = 1;
289                                         SQLBindParameter( sth, 1,
290                                                 SQL_PARAM_OUTPUT,
291                                                 SQL_C_ULONG, SQL_INTEGER,
292                                                 0, 0, &prc, 0, 0 );
293                                 } else {
294                                         pno = 0;
295                                 }
296                                 po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
297                                 SQLBindParameter( sth, pno + 1 + po,
298                                         SQL_PARAM_INPUT, 
299                                         SQL_C_ULONG, SQL_INTEGER,
300                                         0, 0, &e_id->keyval, 0, 0 );
301
302                                 /*
303                                  * check for syntax needed here 
304                                  * maybe need binary bind?
305                                  */
306                                 SQLBindParameter( sth, pno + 2 - po,
307                                         SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
308                                         0, 0, at_val->bv_val, 
309                                         at_val->bv_len, 0 );
310
311                                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
312                                         "executing '%s'\n", 
313                                         at->delete_proc, 0, 0 );
314                                 rc = SQLExecDirect( sth, at->delete_proc,
315                                                 SQL_NTS );
316                                 if ( rc != SQL_SUCCESS ) {
317                                         Debug( LDAP_DEBUG_TRACE,
318                                                 "backsql_modify(): "
319                                                 "delete_proc execution "
320                                                 "failed\n", 0, 0, 0 );
321                                         backsql_PrintErrors( bi->db_env,
322                                                         dbh, sth, rc );
323                                 }
324 #ifdef BACKSQL_REALLOC_STMT
325                                 SQLFreeStmt( sth, SQL_DROP );
326                                 SQLAllocStmt( dbh, &sth );
327 #endif /* BACKSQL_REALLOC_STMT */
328                         }
329                         break;
330                 }
331 #ifndef BACKSQL_REALLOC_STMT
332                 SQLFreeStmt( sth, SQL_RESET_PARAMS );
333 #else /* BACKSQL_REALLOC_STMT */
334                 SQLFreeStmt( sth, SQL_DROP );
335 #endif /* BACKSQL_REALLOC_STMT */
336         }
337
338 #ifndef BACKSQL_REALLOC_STMT
339         SQLFreeStmt( sth, SQL_DROP );
340 #endif /* BACKSQL_REALLOC_STMT */
341
342         /*
343          * FIXME: should fail in case one change fails?
344          */
345         return LDAP_SUCCESS;
346 }
347
348 int
349 backsql_modify(
350         BackendDB       *be,
351         Connection      *conn,
352         Operation       *op,
353         struct berval   *dn,
354         struct berval   *ndn,
355         Modifications   *modlist )
356 {
357         backsql_info            *bi = (backsql_info*)be->be_private;
358         SQLHDBC                 dbh;
359         backsql_oc_map_rec      *oc = NULL;
360         backsql_entryID         e_id;
361         int                     res;
362
363         /*
364          * FIXME: in case part of the operation cannot be performed
365          * (missing mapping, SQL write fails or so) the entire operation
366          * should be rolled-back
367          */
368
369         Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
370                 ndn->bv_val, 0, 0 );
371         res = backsql_get_db_conn( be, conn, &dbh );
372         if ( res != LDAP_SUCCESS ) {
373                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
374                         "could not get connection handle - exiting\n", 
375                         0, 0, 0 );
376                 /*
377                  * FIXME: we don't want to send back 
378                  * excessively detailed messages
379                  */
380                 send_ldap_result( conn, op, res, "", 
381                                 res == LDAP_OTHER ?  "SQL-backend error" : "", 
382                                 NULL, NULL );
383                 return 1;
384         }
385
386         res = backsql_dn2id( bi, &e_id, dbh, ndn );
387         if ( res != LDAP_SUCCESS ) {
388                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
389                         "could not lookup entry id\n", 0, 0, 0 );
390                 send_ldap_result( conn, op, res , "", 
391                                 res == LDAP_OTHER ? "SQL-backend error" : "",
392                                 NULL, NULL );
393                 return 1;
394         }
395
396         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
397                 "modifying entry '%s' (id=%ld)\n", 
398                 e_id.dn.bv_val, e_id.id, 0 );
399
400         oc = backsql_id2oc( bi, e_id.oc_id );
401         if ( oc == NULL ) {
402                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
403                         "cannot determine objectclass of entry -- aborting\n",
404                         0, 0, 0 );
405                 /*
406                  * FIXME: should never occur, since the entry was built!!!
407                  */
408
409                 /*
410                  * FIXME: we don't want to send back 
411                  * excessively detailed messages
412                  */
413                 send_ldap_result( conn, op, LDAP_OTHER, "",
414                                 "SQL-backend error", NULL, NULL );
415                 return 1;
416         }
417
418         res = backsql_modify_internal( bi, dbh, oc, &e_id, modlist );
419         if ( res == LDAP_SUCCESS ) {
420                 /*
421                  * Commit only if all operations succeed
422                  *
423                  * FIXME: backsql_modify_internal() does not fail 
424                  * if add/delete operations are not available, or
425                  * if a multiple value add actually results in a replace, 
426                  * or if a single operation on an attribute fails 
427                  * for any reason
428                  */
429                 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
430         }
431         send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
432         Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
433
434         return 0;
435 }
436
437 int
438 backsql_modrdn(
439         BackendDB       *be,
440         Connection      *conn,
441         Operation       *op,
442         struct berval   *dn,
443         struct berval   *ndn,
444         struct berval   *newrdn,
445         struct berval   *nnewrdn,
446         int             deleteoldrdn,
447         struct berval   *newSuperior,
448         struct berval   *nnewSuperior )
449 {
450         backsql_info            *bi = (backsql_info*)be->be_private;
451         SQLHDBC                 dbh;
452         SQLHSTMT                sth;
453         RETCODE                 rc;
454         backsql_entryID         e_id, pe_id, new_pid;
455         backsql_oc_map_rec      *oc = NULL;
456         int                     res;
457         struct berval           p_dn, p_ndn,
458                                 *new_pdn = NULL, *new_npdn = NULL,
459                                 new_dn, new_ndn;
460         const char              *text = NULL;
461         LDAPRDN                 *new_rdn = NULL;
462         LDAPRDN                 *old_rdn = NULL;
463         Modifications           *mod;
464  
465         Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
466                         "newrdn='%s', newSuperior='%s'\n",
467                         dn->bv_val, newrdn->bv_val, 
468                         newSuperior ? newSuperior->bv_val : "(NULL)" );
469         res = backsql_get_db_conn( be, conn, &dbh );
470         if ( res != LDAP_SUCCESS ) {
471                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
472                         "could not get connection handle - exiting\n", 
473                         0, 0, 0 );
474                 send_ldap_result( conn, op, res, "",
475                                 res == LDAP_OTHER ?  "SQL-backend error" : "",
476                                 NULL, NULL );
477                 return 1;
478         }
479
480         res = backsql_dn2id( bi, &e_id, dbh, ndn );
481         if ( res != LDAP_SUCCESS ) {
482                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
483                         "could not lookup entry id\n", 0, 0, 0 );
484                 send_ldap_result( conn, op, res, "",
485                                 res == LDAP_OTHER ?  "SQL-backend error" : "",
486                                 NULL, NULL );
487                 return 1;
488         }
489
490         /*
491          * FIXME: check whether entry has children
492          */
493
494         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
495                 e_id.id, 0, 0 );
496
497         dnParent( dn, &p_dn );
498         dnParent( ndn, &p_ndn );
499
500         if ( newSuperior ) {
501                 /*
502                  * namingContext "" is not supported
503                  */
504                 if ( newSuperior->bv_len == 0 ) {
505                         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
506                                 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
507                         send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, 
508                                         "", "not allowed within namingContext", 
509                                         NULL, NULL );
510                         goto modrdn_return;
511                 }
512
513                 new_pdn = newSuperior;
514                 new_npdn = nnewSuperior;
515
516         } else {
517                 new_pdn = &p_dn;
518                 new_npdn = &p_ndn;
519         }
520
521         if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
522                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
523                         "newSuperior is equal to old parent - ignored\n",
524                         0, 0, 0 );
525                 newSuperior = NULL;
526         }
527
528         if ( newSuperior && dn_match( ndn, new_npdn ) ) {
529                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
530                         "newSuperior is equal to entry being moved "
531                         "- aborting\n", 0, 0, 0 );
532                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", 
533                                 NULL, NULL, NULL );
534                 goto modrdn_return;
535         }
536
537         build_new_dn( &new_dn, new_pdn, newrdn ); 
538         if ( dnNormalize2( NULL, &new_dn, &new_ndn ) != LDAP_SUCCESS ) {
539                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
540                         "new dn is invalid ('%s') - aborting\n",
541                         new_dn.bv_val, 0, 0 );
542                 send_ldap_result( conn, op, LDAP_INVALID_DN_SYNTAX, "", 
543                                 NULL, NULL, NULL );
544                 goto modrdn_return;
545         }
546         
547         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): new entry dn is '%s'\n",
548                         new_dn.bv_val, 0, 0 );
549
550         res = backsql_dn2id( bi, &pe_id, dbh, &p_ndn );
551         if ( res != LDAP_SUCCESS ) {
552                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
553                         "could not lookup old parent entry id\n", 0, 0, 0 );
554                 send_ldap_result( conn, op, res, "", 
555                                 res == LDAP_OTHER ? "SQL-backend error" : "",
556                                 NULL, NULL );
557                 goto modrdn_return;
558         }
559
560         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
561                 "old parent entry id is %ld\n", pe_id.id, 0, 0 );
562
563         res = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
564         if ( res != LDAP_SUCCESS ) {
565                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
566                         "could not lookup new parent entry id\n", 0, 0, 0 );
567                 send_ldap_result( conn, op, res, "",
568                                 res == LDAP_OTHER ? "SQL-backend error" : "",
569                                 NULL, NULL );
570                 goto modrdn_return;
571         }
572         
573         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
574                 "new parent entry id is %ld\n", new_pid.id, 0, 0 );
575
576  
577         Debug(  LDAP_DEBUG_TRACE, "backsql_modrdn(): "
578                 "executing delentry_query\n", 0, 0, 0 );
579         SQLAllocStmt( dbh, &sth );
580         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
581                         0, 0, &e_id.id, 0, 0 );
582         rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
583         if ( rc != SQL_SUCCESS ) {
584                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
585                         "failed to delete record from ldap_entries\n",
586                         0, 0, 0 );
587                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
588                 send_ldap_result( conn, op, LDAP_OTHER, "",
589                                 "SQL-backend error", NULL, NULL );
590                 goto modrdn_return;
591         }
592
593         SQLFreeStmt( sth, SQL_RESET_PARAMS );
594
595         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
596                 "executing insentry_query\n", 0, 0, 0 );
597         backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
598         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
599                         0, 0, &e_id.oc_id, 0, 0 );
600         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
601                         0, 0, &new_pid.id, 0, 0 );
602         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
603                         0, 0, &e_id.keyval, 0, 0 );
604         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
605         if ( rc != SQL_SUCCESS ) {
606                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
607                         "could not insert ldap_entries record\n", 0, 0, 0 );
608                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
609                 send_ldap_result( conn, op, LDAP_OTHER, "",
610                                 "SQL-backend error", NULL, NULL );
611                 goto modrdn_return;
612         }
613
614         /* Get attribute type and attribute value of our new rdn, we will
615          * need to add that to our new entry
616          */
617         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text, 
618                                 LDAP_DN_FORMAT_LDAP ) ) {
619 #ifdef NEW_LOGGING
620                 LDAP_LOG ( OPERATION, ERR, 
621                         "backsql_modrdn: can't figure out "
622                         "type(s)/values(s) of newrdn\n", 
623                         0, 0, 0 );
624 #else
625                 Debug( LDAP_DEBUG_TRACE,
626                         "backsql_modrdn: can't figure out "
627                         "type(s)/values(s) of newrdn\n", 
628                         0, 0, 0 );
629 #endif
630                 rc = LDAP_INVALID_DN_SYNTAX;
631                 goto modrdn_return;
632         }
633
634 #ifdef NEW_LOGGING
635         LDAP_LOG ( OPERATION, RESULTS, 
636                 "backsql_modrdn: new_rdn_type=\"%s\", "
637                 "new_rdn_val=\"%s\"\n",
638                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
639                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
640 #else
641         Debug( LDAP_DEBUG_TRACE,
642                 "backsql_modrdn: new_rdn_type=\"%s\", "
643                 "new_rdn_val=\"%s\"\n",
644                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
645                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
646 #endif
647
648         if ( deleteoldrdn ) {
649                 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
650                         LDAP_DN_FORMAT_LDAP ) ) {
651 #ifdef NEW_LOGGING
652                         LDAP_LOG ( OPERATION, ERR, 
653                                 "backsql_modrdn: can't figure out "
654                                 "type(s)/values(s) of old_rdn\n", 
655                                 0, 0, 0 );
656 #else
657                         Debug( LDAP_DEBUG_TRACE,
658                                 "backsql_modrdn: can't figure out "
659                                 "the old_rdn type(s)/value(s)\n", 
660                                 0, 0, 0 );
661 #endif
662                         rc = LDAP_OTHER;
663                         goto modrdn_return;             
664                 }
665         }
666
667         res = slap_modrdn2mods( NULL, NULL, NULL, NULL, old_rdn, new_rdn, 
668                         deleteoldrdn, &mod );
669         if ( res != LDAP_SUCCESS ) {
670                 goto modrdn_return;
671         }
672
673         oc = backsql_id2oc( bi, e_id.oc_id );
674         res = backsql_modify_internal( bi, dbh, oc, &e_id, mod );
675
676         if ( res != LDAP_SUCCESS ) {
677                 goto modrdn_return;
678         }
679
680         /*
681          * Commit only if all operations succeed
682          *
683          * FIXME: backsql_modify_internal() does not fail 
684          * if add/delete operations are not available, or
685          * if a multiple value add actually results in a replace, 
686          * or if a single operation on an attribute fails for any
687          * reason
688          */
689         SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
690
691 modrdn_return:
692         SQLFreeStmt( sth, SQL_DROP );
693
694         if ( new_dn.bv_val ) {
695                 ch_free( new_dn.bv_val );
696         }
697         
698         if ( new_ndn.bv_val ) {
699                 ch_free( new_ndn.bv_val );
700         }
701         
702         /* LDAP v2 supporting correct attribute handling. */
703         if ( new_rdn != NULL ) {
704                 ldap_rdnfree( new_rdn );
705         }
706         if ( old_rdn != NULL ) {
707                 ldap_rdnfree( old_rdn );
708         }
709         if( mod != NULL ) {
710                 Modifications *tmp;
711                 for (; mod; mod=tmp ) {
712                         tmp = mod->sml_next;
713                         free( mod );
714                 }
715         }
716
717         send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
718
719         Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
720         return 0;
721 }
722
723 int
724 backsql_add(
725         BackendDB       *be,
726         Connection      *conn,
727         Operation       *op,
728         Entry           *e )
729 {
730         backsql_info            *bi = (backsql_info*)be->be_private;
731         SQLHDBC                 dbh;
732         SQLHSTMT                sth;
733         unsigned long           new_keyval = 0;
734         long                    i;
735         RETCODE                 rc;
736         backsql_oc_map_rec      *oc = NULL;
737         backsql_at_map_rec      *at_rec = NULL;
738         backsql_entryID         e_id, parent_id;
739         int                     res;
740         Attribute               *at;
741         struct berval           *at_val;
742         struct berval           pdn;
743         /* first parameter no, parameter order */
744         SQLUSMALLINT            pno, po;
745         /* procedure return code */
746         int                     prc;
747
748         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n",
749                         e->e_dn, 0, 0 );
750
751         for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
752                 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
753                         /*
754                          * FIXME: only the objectClass provided first
755                          * is considered when creating a new entry
756                          */
757                         oc = backsql_name2oc( bi, &at->a_vals[ 0 ] );
758                         break;
759                 }
760         }
761
762         if ( oc == NULL ) {
763                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
764                         "cannot determine objectclass of entry -- aborting\n",
765                         0, 0, 0 );
766                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
767                                 "operation not permitted within namingContext",
768                                 NULL, NULL );
769                 return 1;
770         }
771
772         if ( oc->create_proc == NULL ) {
773                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
774                         "create procedure is not defined for this objectclass "
775                         "- aborting\n", 0, 0, 0 );
776                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
777                                 "operation not permitted within namingContext",
778                                 NULL, NULL );
779                 return 1;
780         }
781
782         prc = backsql_get_db_conn( be, conn, &dbh );
783         if ( prc != LDAP_SUCCESS ) {
784                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
785                         "could not get connection handle - exiting\n", 
786                         0, 0, 0 );
787                 send_ldap_result( conn, op, prc, "",
788                                 prc == LDAP_OTHER ?  "SQL-backend error" : "",
789                                 NULL, NULL );
790                 return 1;
791         }
792
793         /*
794          * Check if entry exists
795          */
796         res = backsql_dn2id( bi, &e_id, dbh, &e->e_name );
797         if ( res == LDAP_SUCCESS ) {
798                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
799                         "entry '%s' exists\n",
800                         e->e_name.bv_val, 0, 0 );
801                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", 
802                                 NULL, NULL, NULL );
803                 return 1;
804         }
805
806         /*
807          * Check if parent exists
808          */
809         dnParent( &e->e_name, &pdn );
810         res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
811         if ( res != LDAP_SUCCESS ) {
812                 
813                 /*
814                  * NO SUCH OBJECT seems more appropriate
815                  */
816                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
817                         "could not lookup parent entry for new record '%s'\n",
818                         pdn.bv_val, 0, 0 );
819
820                 if ( res != LDAP_NO_SUCH_OBJECT ) {
821                         send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
822                         return 1;
823                 }
824
825                 /*
826                  * Look for matched
827                  */
828                 while ( 1 ) {
829                         struct berval   dn;
830                         char            *matched = "";
831
832                         dn = pdn;
833                         dnParent( &dn, &pdn );
834
835                         /*
836                          * Empty DN ("") defaults to LDAP_SUCCESS
837                          */
838                         res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
839                         switch ( res ) {
840                         case LDAP_NO_SUCH_OBJECT:
841                                 if ( pdn.bv_len > 0 ) {
842                                         break;
843                                 }
844                                 /* fail over to next case */
845                                 
846                         case LDAP_SUCCESS:
847                                 matched = pdn.bv_val;
848                                 /* fail over to next case */
849
850                         default:
851                                 send_ldap_result( conn, op, res, matched, 
852                                                 NULL, NULL, NULL );
853                                 return 1;
854                         } 
855                 }
856         }
857
858         /*
859          * create_proc is executed; if expect_return is set, then
860          * an output parameter is bound, which should contain 
861          * the id of the added row; otherwise the procedure
862          * is expected to return the id as the first column of a select
863          */
864
865 #ifndef BACKSQL_REALLOC_STMT
866         rc = SQLAllocStmt( dbh, &sth );
867 #else /* BACKSQL_REALLOC_STMT */
868         rc = backsql_Prepare( dbh, &sth, oc->create_proc, 0 );
869 #endif /* BACKSQL_REALLOC_STMT */
870         if ( rc != SQL_SUCCESS ) {
871                 send_ldap_result( conn, op, LDAP_OTHER, "",
872                                 "SQL-backend error", NULL, NULL );
873                 return 1;
874         }
875
876         if ( BACKSQL_IS_ADD( oc->expect_return ) ) {
877                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
878                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
879         }
880
881         Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s'\n",
882                 oc->create_proc, 0, 0 );
883 #ifndef BACKSQL_REALLOC_STMT
884         rc = SQLExecDirect( sth, oc->create_proc, SQL_NTS );
885 #else /* BACKSQL_REALLOC_STMT */
886         rc = SQLExecute( sth );
887 #endif /* BACKSQL_REALLOC_STMT */
888         if ( rc != SQL_SUCCESS ) {
889                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
890                         "create_proc execution failed\n", 0, 0, 0 );
891                 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
892                 SQLFreeStmt( sth, SQL_DROP );
893                 send_ldap_result( conn, op, LDAP_OTHER, "",
894                                 "SQL-backend error", NULL, NULL );
895                 return 1;
896         }
897
898         if ( !BACKSQL_IS_ADD( oc->expect_return ) ) {
899                 SWORD           ncols;
900                 SQLINTEGER      is_null;
901
902                 /*
903                  * the query to know the id of the inserted entry
904                  * must be embedded in the create procedure
905                  */
906                 rc = SQLNumResultCols( sth, &ncols );
907                 if ( rc != SQL_SUCCESS ) {
908                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
909                                 "create_proc result evaluation failed\n",
910                                 0, 0, 0 );
911                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
912                         SQLFreeStmt( sth, SQL_DROP );
913                         send_ldap_result( conn, op, LDAP_OTHER, "",
914                                         "SQL-backend error", NULL, NULL );
915                         return 1;
916
917                 } else if ( ncols != 1 ) {
918                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
919                                 "create_proc result is bogus\n",
920                                 0, 0, 0 );
921                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
922                         SQLFreeStmt( sth, SQL_DROP );
923                         send_ldap_result( conn, op, LDAP_OTHER, "",
924                                         "SQL-backend error", NULL, NULL );
925                         return 1;
926                 }
927
928 #if 0
929                 {
930                         SQLCHAR         colname[ 64 ];
931                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
932                         UDWORD          col_prec;
933
934                         /*
935                          * FIXME: check whether col_type is compatible,
936                          * if it can be null and so on ...
937                          */
938                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
939                                         &colname[ 0 ], 
940                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
941                                         &name_len, &col_type,
942                                         &col_prec, &col_scale, &col_null );
943                 }
944 #endif
945
946                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
947                                 (SQLPOINTER)&new_keyval, 
948                                 (SQLINTEGER)sizeof( new_keyval ), 
949                                 &is_null );
950
951                 rc = SQLFetch( sth );
952
953 #if 0
954                 /*
955                  * FIXME: what does is_null mean?
956                  */
957                 if ( is_null ) {
958                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
959                                 "create_proc result is null\n",
960                                 0, 0, 0 );
961                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
962                         SQLFreeStmt( sth, SQL_DROP );
963                         send_ldap_result( conn, op, LDAP_OTHER, "",
964                                         "SQL-backend error", NULL, NULL );
965                         return 1;
966                 }
967 #endif
968         }
969
970 #ifndef BACKSQL_REALLOC_STMT
971         SQLFreeStmt( sth, SQL_RESET_PARAMS );
972 #else /* BACKSQL_REALLOC_STMT */
973         SQLFreeStmt( sth, SQL_DROP );
974 #endif /* BACKSQL_REALLOC_STMT */
975
976         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
977                 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
978
979         for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
980                 SQLUSMALLINT    currpos;
981
982                 if ( at->a_vals[ 0 ].bv_val == NULL ) {
983                         continue;
984                 }
985
986                 at_rec = backsql_ad2at( oc, at->a_desc ); 
987   
988                 if ( at_rec == NULL ) {
989                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
990                                 "attribute '%s' is not registered "
991                                 "in objectclass '%s'\n",
992                                 at->a_desc->ad_cname.bv_val,
993                                 oc->name.bv_val, 0 );
994                         continue;
995                 }
996                 
997                 if ( at_rec->add_proc == NULL ) {
998                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
999                                 "add procedure is not defined "
1000                                 "for attribute '%s'\n",
1001                                 at->a_desc->ad_cname.bv_val, 0, 0 );
1002                         continue;
1003                 }
1004
1005 #ifdef BACKSQL_REALLOC_STMT
1006                 rc = backsql_Prepare( dbh, &sth, at_rec->add_proc, 0 );
1007                 if ( rc != SQL_SUCCESS ) {
1008                         continue;
1009                 }
1010 #endif /* BACKSQL_REALLOC_STMT */
1011
1012                 if ( BACKSQL_IS_ADD( at_rec->expect_return ) ) {
1013                         pno = 1;
1014                         SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
1015                                         SQL_C_ULONG, SQL_INTEGER,
1016                                         0, 0, &prc, 0, 0 );
1017                 } else {
1018                         pno = 0;
1019                 }
1020
1021                 po = ( BACKSQL_IS_ADD( at_rec->param_order ) ) > 0;
1022                 currpos = pno + 1 + po;
1023                 SQLBindParameter( sth, currpos,
1024                                 SQL_PARAM_INPUT, SQL_C_ULONG,
1025                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1026                 currpos = pno + 2 - po;
1027
1028                 for ( i = 0, at_val = &at->a_vals[ 0 ];
1029                                 at_val->bv_val != NULL;
1030                                 i++, at_val = &at->a_vals[ i ] ) {
1031
1032                         /*
1033                          * check for syntax needed here 
1034                          * maybe need binary bind?
1035                          */
1036
1037                         backsql_BindParamStr( sth, currpos,
1038                                         at_val->bv_val, at_val->bv_len + 1 );
1039 #ifdef SECURITY_PARANOID
1040                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1041                                 "executing '%s', id=%ld\n", 
1042                                 at_rec->add_proc, new_keyval, 0 );
1043 #else
1044                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1045                                 "executing '%s' with val='%s', id=%ld\n", 
1046                                 at_rec->add_proc, at_val->bv_val, new_keyval );
1047 #endif
1048 #ifndef BACKSQL_REALLOC_STMT
1049                         rc = SQLExecDirect( sth, at_rec->add_proc, SQL_NTS );
1050 #else /* BACKSQL_REALLOC_STMT */
1051                         rc = SQLExecute( sth );
1052 #endif /* BACKSQL_REALLOC_STMT */
1053                         if ( rc != SQL_SUCCESS ) {
1054                                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1055                                         "add_proc execution failed\n", 
1056                                         0, 0, 0 );
1057                                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1058                         }
1059                 }
1060 #ifndef BACKSQL_REALLOC_STMT
1061                 SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
1062 #else /* BACKSQL_REALLOC_STMT */
1063                 SQLFreeStmt( sth, SQL_DROP );
1064 #endif /* BACKSQL_REALLOC_STMT */
1065         }
1066
1067 #ifdef BACKSQL_REALLOC_STMT
1068         rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1069         if ( rc != SQL_SUCCESS ) {
1070                 send_ldap_result( conn, op, LDAP_OTHER, "",
1071                                 "SQL-backend error", NULL, NULL );
1072                 return 1;
1073         }
1074 #endif /* BACKSQL_REALLOC_STMT */
1075         backsql_BindParamStr( sth, 1, e->e_name.bv_val, BACKSQL_MAX_DN_LEN );
1076         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1077                         0, 0, &oc->id, 0, 0 );
1078         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1079                         0, 0, &parent_id.id, 0, 0 );
1080         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1081                         0, 0, &new_keyval, 0, 0 );
1082
1083         Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s' for dn '%s'\n",
1084                         bi->insentry_query, e->e_name.bv_val, 0 );
1085         Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, "
1086                         "keyval=%ld\n", oc->id, parent_id.id, new_keyval );
1087 #ifndef BACKSQL_REALLOC_STMT
1088         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1089 #else /* BACKSQL_REALLOC_STMT */
1090         rc = SQLExecute( sth );
1091 #endif /* BACKSQL_REALLOC_STMT */
1092         if ( rc != SQL_SUCCESS ) {
1093                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1094                         "could not insert ldap_entries record\n", 0, 0, 0 );
1095                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1096                 
1097                 /*
1098                  * execute delete_proc to delete data added !!!
1099                  */
1100                 SQLFreeStmt( sth, SQL_DROP );
1101                 send_ldap_result( conn, op, LDAP_OTHER, "", 
1102                                 "SQL-backend error", NULL, NULL );
1103                 return 1;
1104         }
1105         
1106         SQLFreeStmt( sth, SQL_DROP );
1107
1108         /*
1109          * Commit only if all operations succeed
1110          *
1111          * FIXME: backsql_add() does not fail if add operations 
1112          * are not available for some attributes, or if
1113          * a multiple value add actually results in a replace, 
1114          * or if a single operation on an attribute fails 
1115          * for any reason
1116          */
1117         SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1118
1119         send_ldap_result( conn, op, LDAP_SUCCESS, "",
1120                         NULL, NULL, NULL );
1121         return 0;
1122 }
1123
1124 int
1125 backsql_delete(
1126         BackendDB       *be,
1127         Connection      *conn,
1128         Operation       *op,
1129         struct berval   *dn,
1130         struct berval   *ndn )
1131 {
1132         backsql_info            *bi = (backsql_info*)be->be_private;
1133         SQLHDBC                 dbh;
1134         SQLHSTMT                sth;
1135         RETCODE                 rc;
1136         backsql_oc_map_rec      *oc = NULL;
1137         backsql_entryID         e_id;
1138         int                     res;
1139         /* first parameter no */
1140         SQLUSMALLINT            pno;
1141
1142         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
1143                         ndn->bv_val, 0, 0 );
1144         res = backsql_get_db_conn( be, conn, &dbh );
1145         if ( res != LDAP_SUCCESS ) {
1146                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1147                         "could not get connection handle - exiting\n", 
1148                         0, 0, 0 );
1149                 send_ldap_result( conn, op, res, "", 
1150                                 res == LDAP_OTHER ? "SQL-backend error" : "",
1151                                 NULL, NULL );
1152                 return 1;
1153         }
1154         
1155         res = backsql_dn2id( bi, &e_id, dbh, ndn );
1156         if ( res != LDAP_SUCCESS ) {
1157                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1158                         "could not lookup entry id\n", 0, 0, 0 );
1159                 send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
1160                 return 1;
1161         }
1162
1163         oc = backsql_id2oc( bi, e_id.oc_id );
1164         if ( oc == NULL ) {
1165                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1166                         "cannot determine objectclass of entry "
1167                         "-- aborting\n", 0, 0, 0 );
1168                 send_ldap_result( conn, op, LDAP_OTHER, "",
1169                                 "SQL-backend error", NULL, NULL );
1170                 return 1;
1171         }
1172
1173         if ( oc->delete_proc == NULL ) {
1174                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1175                         "delete procedure is not defined "
1176                         "for this objectclass - aborting\n", 0, 0, 0 );
1177                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
1178                                 "operation not supported for required DN", 
1179                                 NULL, NULL );
1180                 return 1;
1181         }
1182
1183         SQLAllocStmt( dbh, &sth );
1184         if ( BACKSQL_IS_DEL( oc->expect_return ) ) {
1185                 pno = 1;
1186                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1187                                 SQL_INTEGER, 0, 0, &rc, 0, 0 );
1188         } else {
1189                 pno = 0;
1190         }
1191
1192         SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT, 
1193                         SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 );
1194
1195         Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n",
1196                         oc->delete_proc, 0, 0 );
1197         rc = SQLExecDirect( sth, oc->delete_proc, SQL_NTS );
1198         if ( rc != SQL_SUCCESS ) {
1199                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1200                         "delete_proc execution failed\n", 0, 0, 0 );
1201                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1202                 SQLFreeStmt( sth, SQL_DROP );
1203                 send_ldap_result( conn, op, LDAP_OTHER, "",
1204                                 "SQL-backend error", NULL, NULL );
1205                 return 1;
1206         }
1207 #ifndef BACKSQL_REALLOC_STMT
1208         SQLFreeStmt( sth, SQL_RESET_PARAMS );
1209 #else /* BACKSQL_REALLOC_STMT */
1210         SQLFreeStmt( sth, SQL_DROP );
1211         SQLAllocStmt( dbh, &sth );
1212 #endif /* BACKSQL_REALLOC_STMT */
1213
1214         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
1215                         0, 0, &e_id.id, 0, 0 );
1216         rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
1217         if ( rc != SQL_SUCCESS ) {
1218                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1219                         "failed to delete record from ldap_entries\n", 
1220                         0, 0, 0 );
1221                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1222                 SQLFreeStmt( sth, SQL_DROP );
1223                 send_ldap_result( conn, op, LDAP_OTHER, "",
1224                                 "SQL-backend error", NULL, NULL );
1225                 return 1;
1226         }
1227         
1228         SQLFreeStmt( sth, SQL_DROP );
1229
1230         /*
1231          * Commit only if all operations succeed
1232          *
1233          * FIXME: backsql_add() does not fail if add operations 
1234          * are not available for some attributes, or if
1235          * a multiple value add actually results in a replace, 
1236          * or if a single operation on an attribute fails 
1237          * for any reason
1238          */
1239         SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
1240
1241         send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
1242         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
1243         return 0;
1244 }
1245
1246 #endif /* SLAPD_SQL */
1247