]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/modify.c
trace illegal condition in backsql_strfcat
[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 7.0 doesn't work without :(
27  */
28 #define BACKSQL_REALLOC_STMT
29
30 /*
31  * Skip:
32  * - the first occurrence of objectClass, which is used
33  *   to determine how to bulid the SQL entry (FIXME ?!?)
34  * - operational attributes
35  *   empty attributes (FIXME ?!?)
36  */
37 #define backsql_attr_skip(ad,vals) \
38         ( \
39                 ( (ad) == slap_schema.si_ad_objectClass \
40                                 && (vals)[ 1 ].bv_val == NULL ) \
41                 || is_at_operational( (ad)->ad_type ) \
42                 || ( (vals)[ 0 ].bv_val == NULL ) \
43         )
44
45 static int
46 backsql_modify_internal(
47         backsql_info            *bi,
48         SQLHDBC                 dbh, 
49         backsql_oc_map_rec      *oc,
50         backsql_entryID         *e_id,
51         Modifications           *modlist,
52         const char              **text )
53 {
54         RETCODE         rc;
55         SQLHSTMT        sth;
56         Modifications   *ml;
57         int             res = LDAP_SUCCESS;
58
59         Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
60                 "traversing modifications list\n", 0, 0, 0 );
61
62         *text = NULL;
63
64 #ifndef BACKSQL_REALLOC_STMT
65         SQLAllocStmt( dbh, &sth );
66 #endif /* BACKSQL_REALLOC_STMT */
67
68         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
69                 AttributeDescription    *ad;
70                 backsql_at_map_rec      *at = NULL;
71                 struct berval           *at_val;
72                 Modification            *c_mod;
73                 int                     i;
74                 /* first parameter no, parameter order */
75                 SQLUSMALLINT            pno, po;
76                 /* procedure return code */
77                 int                     prc;
78
79 #ifdef BACKSQL_REALLOC_STMT
80                 SQLAllocStmt( dbh, &sth );
81 #endif /* BACKSQL_REALLOC_STMT */
82
83                 c_mod = &ml->sml_mod;
84                 ad = c_mod->sm_desc;
85
86                 Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
87                         "modifying attribute '%s'\n",
88                         ad->ad_cname.bv_val, 0, 0 );
89
90                 if ( backsql_attr_skip( ad, c_mod->sm_bvalues ) ) {
91                         continue;
92                 }
93
94                 at = backsql_ad2at( oc, ad );
95                 if ( at == NULL ) {
96                         Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
97                                 "attribute provided is not registered "
98                                 "in objectClass '%s'\n",
99                                 ad->ad_cname.bv_val, 0, 0 );
100
101                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
102                                 res = LDAP_UNWILLING_TO_PERFORM;
103                                 *text = "operation not permitted "
104                                         "within namingContext";
105                                 goto done;
106                         }
107
108                         continue;
109                 }
110   
111                 switch( c_mod->sm_op ) {
112                 case LDAP_MOD_REPLACE: {
113                         SQLHSTMT asth;
114                         BACKSQL_ROW_NTS row;
115                         
116                         Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
117                                 "replacing values for attribute '%s'\n",
118                                 at->ad->ad_cname.bv_val, 0, 0 );
119
120                         if ( at->add_proc == NULL ) {
121                                 Debug( LDAP_DEBUG_TRACE,
122                                         "backsql_modify_internal(): "
123                                         "add procedure is not defined "
124                                         "for attribute '%s' "
125                                         "- unable to perform replacements\n",
126                                         at->ad->ad_cname.bv_val, 0, 0 );
127
128                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
129                                         res = LDAP_UNWILLING_TO_PERFORM;
130                                         *text = "operation not permitted "
131                                                 "within namingContext";
132                                         goto done;
133                                 }
134
135                                 break;
136                         }
137
138                         if ( at->delete_proc == NULL ) {
139                                 Debug( LDAP_DEBUG_TRACE,
140                                         "backsql_modify_internal(): "
141                                         "delete procedure is not defined "
142                                         "for attribute '%s' "
143                                         "- adding only\n",
144                                         at->ad->ad_cname.bv_val, 0, 0 );
145
146                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
147                                         res = LDAP_UNWILLING_TO_PERFORM;
148                                         *text = "operation not permitted "
149                                                 "within namingContext";
150                                         goto done;
151                                 }
152
153                                 goto add_only;
154                         }
155                         
156 del_all:
157                         rc = backsql_Prepare( dbh, &asth, at->query, 0 );
158                         if ( rc != SQL_SUCCESS ) {
159                                 Debug( LDAP_DEBUG_TRACE,
160                                         "backsql_modify_internal(): "
161                                         "error preparing query\n", 0, 0, 0 );
162                                 backsql_PrintErrors( bi->db_env, dbh, 
163                                                 asth, rc );
164
165                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
166                                         res = LDAP_OTHER;
167                                         *text = "SQL-backend error";
168                                         goto done;
169                                 }
170
171                                 break;
172                         }
173
174                         rc = backsql_BindParamID( asth, 1, &e_id->keyval );
175                         if ( rc != SQL_SUCCESS ) {
176                                 Debug( LDAP_DEBUG_TRACE,
177                                         "backsql_modify_internal(): "
178                                         "error binding key value parameter\n",
179                                         0, 0, 0 );
180                                 backsql_PrintErrors( bi->db_env, dbh, 
181                                                 asth, rc );
182                                 SQLFreeStmt( asth, SQL_DROP );
183
184                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
185                                         res = LDAP_OTHER;
186                                         *text = "SQL-backend error";
187                                         goto done;
188                                 }
189
190                                 break;
191                         }
192                         
193                         rc = SQLExecute( asth );
194                         if ( !BACKSQL_SUCCESS( rc ) ) {
195                                 Debug( LDAP_DEBUG_TRACE,
196                                         "backsql_modify_internal(): "
197                                         "error executing attribute query\n",
198                                         0, 0, 0 );
199                                 backsql_PrintErrors( bi->db_env, dbh, 
200                                                 asth, rc );
201                                 SQLFreeStmt( asth, SQL_DROP );
202
203                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
204                                         res = LDAP_OTHER;
205                                         *text = "SQL-backend error";
206                                         goto done;
207                                 }
208
209                                 break;
210                         }
211
212                         backsql_BindRowAsStrings( asth, &row );
213                         rc = SQLFetch( asth );
214                         for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
215                                 for ( i = 0; i < row.ncols; i++ ) {
216                                         if ( BACKSQL_IS_DEL( at->expect_return ) ) {
217                                                 pno = 1;
218                                                 SQLBindParameter(sth, 1,
219                                                         SQL_PARAM_OUTPUT,
220                                                         SQL_C_ULONG,
221                                                         SQL_INTEGER,
222                                                         0, 0, &prc, 0, 0 );
223                                         } else {
224                                                 pno = 0;
225                                         }
226                                         po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
227                                         SQLBindParameter( sth, pno + 1 + po,
228                                                 SQL_PARAM_INPUT,
229                                                 SQL_C_ULONG, SQL_INTEGER,
230                                                 0, 0, &e_id->keyval, 0, 0 );
231
232                                         /*
233                                          * check for syntax needed here 
234                                          * maybe need binary bind?
235                                          */
236                                         SQLBindParameter(sth, pno + 2 - po,
237                                                 SQL_PARAM_INPUT,
238                                                 SQL_C_CHAR, SQL_CHAR,
239                                                 0, 0, row.cols[ i ],
240                                                 strlen( row.cols[ i ] ), 0 );
241                          
242                                         Debug( LDAP_DEBUG_TRACE, 
243                                                 "backsql_modify_internal(): "
244                                                 "executing '%s'\n",
245                                                 at->delete_proc, 0, 0 );
246                                         rc = SQLExecDirect( sth,
247                                                 at->delete_proc, SQL_NTS );
248                                         if ( rc != SQL_SUCCESS ) {
249                                                 Debug( LDAP_DEBUG_TRACE,
250                                                         "backsql_modify_internal(): "
251                                                         "delete_proc "
252                                                         "execution failed\n",
253                                                         0, 0, 0 );
254                                                 backsql_PrintErrors( bi->db_env,
255                                                                 dbh, sth, rc );
256
257                                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
258                                                         res = LDAP_OTHER;
259                                                         *text = "SQL-backend error";
260                                                         goto done;
261                                                 }
262                                         }
263 #ifdef BACKSQL_REALLOC_STMT
264                                         SQLFreeStmt( sth, SQL_DROP );
265                                         SQLAllocStmt( dbh, &sth );
266 #endif /* BACKSQL_REALLOC_STMT */
267                                 }
268                         }
269                         backsql_FreeRow( &row );
270                         SQLFreeStmt( asth, SQL_DROP );
271                 }
272                                        
273                 /*
274                  * PASSTHROUGH - to add new attributes -- do NOT add break
275                  */
276                 case LDAP_MOD_ADD:
277                 case SLAP_MOD_SOFTADD:
278 add_only:;
279                         if ( at->add_proc == NULL ) {
280                                 Debug( LDAP_DEBUG_TRACE,
281                                         "backsql_modify_internal(): "
282                                         "add procedure is not defined "
283                                         "for attribute '%s'\n",
284                                         at->ad->ad_cname.bv_val, 0, 0 );
285
286                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
287                                         res = LDAP_UNWILLING_TO_PERFORM;
288                                         *text = "operation not permitted "
289                                                 "within namingContext";
290                                         goto done;
291                                 }
292
293                                 break;
294                         }
295                         
296                         Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
297                                 "adding new values for attribute '%s'\n",
298                                 at->ad->ad_cname.bv_val, 0, 0 );
299                         for ( i = 0, at_val = c_mod->sm_bvalues;
300                                         at_val->bv_val != NULL; 
301                                         i++, at_val++ ) {
302                                 if ( BACKSQL_IS_ADD( at->expect_return ) ) {
303                                         pno = 1;
304                                         SQLBindParameter( sth, 1,
305                                                 SQL_PARAM_OUTPUT,
306                                                 SQL_C_ULONG, SQL_INTEGER,
307                                                 0, 0, &prc, 0, 0);
308                                 } else {
309                                         pno = 0;
310                                 }
311                                 po = ( BACKSQL_IS_ADD( at->param_order ) ) > 0;
312                                 SQLBindParameter( sth, pno + 1 + po,
313                                         SQL_PARAM_INPUT, 
314                                         SQL_C_ULONG, SQL_INTEGER,
315                                         0, 0, &e_id->keyval, 0, 0 );
316
317                                 /*
318                                  * check for syntax needed here
319                                  * maybe need binary bind?
320                                  */
321                                 SQLBindParameter( sth, pno + 2 - po,
322                                         SQL_PARAM_INPUT,
323                                         SQL_C_CHAR, SQL_CHAR,
324                                         0, 0, at_val->bv_val, 
325                                         at_val->bv_len, 0 );
326
327                                 Debug( LDAP_DEBUG_TRACE,
328                                         "backsql_modify_internal(): "
329                                         "executing '%s'\n", 
330                                         at->add_proc, 0, 0 );
331                                 rc = SQLExecDirect( sth, at->add_proc, 
332                                                 SQL_NTS );
333                                 if ( rc != SQL_SUCCESS ) {
334                                         Debug( LDAP_DEBUG_TRACE,
335                                                 "backsql_modify_internal(): "
336                                                 "add_proc execution failed\n",
337                                                 0, 0, 0 );
338                                         backsql_PrintErrors( bi->db_env,
339                                                         dbh, sth, rc );
340
341                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
342                                                 res = LDAP_OTHER;
343                                                 *text = "SQL-backend error";
344                                                 goto done;
345                                         }
346                                 }
347 #ifdef BACKSQL_REALLOC_STMT
348                                 SQLFreeStmt( sth, SQL_DROP );
349                                 SQLAllocStmt( dbh, &sth );
350 #endif /* BACKSQL_REALLOC_STMT */
351                         }
352                         break;
353                         
354                 case LDAP_MOD_DELETE:
355                         if ( at->delete_proc == NULL ) {
356                                 Debug( LDAP_DEBUG_TRACE,
357                                         "backsql_modify_internal(): "
358                                         "delete procedure is not defined "
359                                         "for attribute '%s'\n",
360                                         at->ad->ad_cname.bv_val, 0, 0 );
361
362                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
363                                         res = LDAP_UNWILLING_TO_PERFORM;
364                                         *text = "operation not permitted "
365                                                 "within namingContext";
366                                         goto done;
367                                 }
368
369                                 break;
370                         }
371
372                         if ( c_mod->sm_bvalues == NULL ) {
373                                 Debug( LDAP_DEBUG_TRACE,
374                                         "backsql_modify_internal(): "
375                                         "no values given to delete "
376                                         "for attribute '%s' "
377                                         "-- deleting all values\n",
378                                         at->ad->ad_cname.bv_val, 0, 0 );
379                                 goto del_all;
380                         }
381
382                         Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
383                                 "deleting values for attribute '%s'\n",
384                                 at->ad->ad_cname.bv_val, 0, 0 );
385
386                         for ( i = 0, at_val = c_mod->sm_bvalues;
387                                         at_val->bv_val != NULL;
388                                         i++, at_val++ ) {
389                                 if ( BACKSQL_IS_DEL( at->expect_return ) ) {
390                                         pno = 1;
391                                         SQLBindParameter( sth, 1,
392                                                 SQL_PARAM_OUTPUT,
393                                                 SQL_C_ULONG, SQL_INTEGER,
394                                                 0, 0, &prc, 0, 0 );
395                                 } else {
396                                         pno = 0;
397                                 }
398                                 po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
399                                 SQLBindParameter( sth, pno + 1 + po,
400                                         SQL_PARAM_INPUT, 
401                                         SQL_C_ULONG, SQL_INTEGER,
402                                         0, 0, &e_id->keyval, 0, 0 );
403
404                                 /*
405                                  * check for syntax needed here 
406                                  * maybe need binary bind?
407                                  */
408                                 SQLBindParameter( sth, pno + 2 - po,
409                                         SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
410                                         0, 0, at_val->bv_val, 
411                                         at_val->bv_len, 0 );
412
413                                 Debug( LDAP_DEBUG_TRACE,
414                                         "backsql_modify_internal(): "
415                                         "executing '%s'\n", 
416                                         at->delete_proc, 0, 0 );
417                                 rc = SQLExecDirect( sth, at->delete_proc,
418                                                 SQL_NTS );
419                                 if ( rc != SQL_SUCCESS ) {
420                                         Debug( LDAP_DEBUG_TRACE,
421                                                 "backsql_modify_internal(): "
422                                                 "delete_proc execution "
423                                                 "failed\n", 0, 0, 0 );
424                                         backsql_PrintErrors( bi->db_env,
425                                                         dbh, sth, rc );
426
427                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
428                                                 res = LDAP_OTHER;
429                                                 *text = "SQL-backend error";
430                                                 goto done;
431                                         }
432                                 }
433 #ifdef BACKSQL_REALLOC_STMT
434                                 SQLFreeStmt( sth, SQL_DROP );
435                                 SQLAllocStmt( dbh, &sth );
436 #endif /* BACKSQL_REALLOC_STMT */
437                         }
438                         break;
439                 }
440 #ifndef BACKSQL_REALLOC_STMT
441                 SQLFreeStmt( sth, SQL_RESET_PARAMS );
442 #else /* BACKSQL_REALLOC_STMT */
443                 SQLFreeStmt( sth, SQL_DROP );
444 #endif /* BACKSQL_REALLOC_STMT */
445         }
446
447 done:;
448         
449 #ifndef BACKSQL_REALLOC_STMT
450         SQLFreeStmt( sth, SQL_DROP );
451 #endif /* BACKSQL_REALLOC_STMT */
452
453         /*
454          * FIXME: should fail in case one change fails?
455          */
456         return res;
457 }
458
459 int
460 backsql_modify(
461         BackendDB       *be,
462         Connection      *conn,
463         Operation       *op,
464         struct berval   *dn,
465         struct berval   *ndn,
466         Modifications   *modlist )
467 {
468         backsql_info            *bi = (backsql_info*)be->be_private;
469         SQLHDBC                 dbh;
470         backsql_oc_map_rec      *oc = NULL;
471         backsql_entryID         e_id;
472         Entry                   e;
473         int                     res;
474         const char              *text = NULL;
475
476         /*
477          * FIXME: in case part of the operation cannot be performed
478          * (missing mapping, SQL write fails or so) the entire operation
479          * should be rolled-back
480          */
481
482         Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
483                 ndn->bv_val, 0, 0 );
484         res = backsql_get_db_conn( be, conn, &dbh );
485         if ( res != LDAP_SUCCESS ) {
486                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
487                         "could not get connection handle - exiting\n", 
488                         0, 0, 0 );
489                 /*
490                  * FIXME: we don't want to send back 
491                  * excessively detailed messages
492                  */
493                 send_ldap_result( conn, op, res, "", 
494                                 res == LDAP_OTHER ?  "SQL-backend error" : "", 
495                                 NULL, NULL );
496                 return 1;
497         }
498
499         res = backsql_dn2id( bi, &e_id, dbh, ndn );
500         if ( res != LDAP_SUCCESS ) {
501                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
502                         "could not lookup entry id\n", 0, 0, 0 );
503                 send_ldap_result( conn, op, res , "", 
504                                 res == LDAP_OTHER ? "SQL-backend error" : "",
505                                 NULL, NULL );
506                 return 1;
507         }
508
509         Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
510                 "modifying entry '%s' (id=%ld)\n", 
511                 e_id.dn.bv_val, e_id.id, 0 );
512
513         oc = backsql_id2oc( bi, e_id.oc_id );
514         if ( oc == NULL ) {
515                 Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
516                         "cannot determine objectclass of entry -- aborting\n",
517                         0, 0, 0 );
518                 /*
519                  * FIXME: should never occur, since the entry was built!!!
520                  */
521
522                 /*
523                  * FIXME: we don't want to send back 
524                  * excessively detailed messages
525                  */
526                 send_ldap_result( conn, op, LDAP_OTHER, "",
527                                 "SQL-backend error", NULL, NULL );
528                 return 1;
529         }
530
531         e.e_attrs = NULL;
532         e.e_name = *dn;
533         e.e_nname = *ndn;
534         if ( !acl_check_modlist( be, conn, op, &e, modlist )) {
535                 res = LDAP_INSUFFICIENT_ACCESS;
536
537         } else {
538                 res = backsql_modify_internal( bi, dbh, oc, &e_id, 
539                                 modlist, &text );
540         }
541
542         if ( res == LDAP_SUCCESS ) {
543                 /*
544                  * Commit only if all operations succeed
545                  *
546                  * FIXME: backsql_modify_internal() does not fail 
547                  * if add/delete operations are not available, or
548                  * if a multiple value add actually results in a replace, 
549                  * or if a single operation on an attribute fails 
550                  * for any reason
551                  */
552                 SQLTransact( SQL_NULL_HENV, dbh, 
553                                 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
554         }
555         send_ldap_result( conn, op, res, NULL, text, NULL, NULL );
556         Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
557
558         return 0;
559 }
560
561 int
562 backsql_modrdn(
563         BackendDB       *be,
564         Connection      *conn,
565         Operation       *op,
566         struct berval   *dn,
567         struct berval   *ndn,
568         struct berval   *newrdn,
569         struct berval   *nnewrdn,
570         int             deleteoldrdn,
571         struct berval   *newSuperior,
572         struct berval   *nnewSuperior )
573 {
574         backsql_info            *bi = (backsql_info*)be->be_private;
575         SQLHDBC                 dbh;
576         SQLHSTMT                sth;
577         RETCODE                 rc;
578         backsql_entryID         e_id, pe_id, new_pid;
579         backsql_oc_map_rec      *oc = NULL;
580         int                     res;
581         struct berval           p_dn, p_ndn,
582                                 *new_pdn = NULL, *new_npdn = NULL,
583                                 new_dn, new_ndn;
584         const char              *text = NULL;
585         LDAPRDN                 *new_rdn = NULL;
586         LDAPRDN                 *old_rdn = NULL;
587         Entry                   e;
588         Modifications           *mod;
589  
590         Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
591                         "newrdn='%s', newSuperior='%s'\n",
592                         dn->bv_val, newrdn->bv_val, 
593                         newSuperior ? newSuperior->bv_val : "(NULL)" );
594         res = backsql_get_db_conn( be, conn, &dbh );
595         if ( res != LDAP_SUCCESS ) {
596                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
597                         "could not get connection handle - exiting\n", 
598                         0, 0, 0 );
599                 send_ldap_result( conn, op, res, "",
600                                 res == LDAP_OTHER ?  "SQL-backend error" : "",
601                                 NULL, NULL );
602                 return 1;
603         }
604
605         res = backsql_dn2id( bi, &e_id, dbh, ndn );
606         if ( res != LDAP_SUCCESS ) {
607                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
608                         "could not lookup entry id\n", 0, 0, 0 );
609                 send_ldap_result( conn, op, res, "",
610                                 res == LDAP_OTHER ?  "SQL-backend error" : "",
611                                 NULL, NULL );
612                 return 1;
613         }
614
615         /*
616          * FIXME: check whether entry has children
617          */
618
619         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
620                 e_id.id, 0, 0 );
621
622         if ( backsql_has_children( bi, dbh, ndn ) == LDAP_COMPARE_TRUE ) {
623                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
624                         "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
625                 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
626                                 NULL, "subtree delete not supported",
627                                 NULL, NULL );
628                 return 1;
629         }
630
631         dnParent( dn, &p_dn );
632         dnParent( ndn, &p_ndn );
633
634         /*
635          * namingContext "" is not supported
636          */
637         if ( p_dn.bv_len == 0 ) {
638                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
639                         "parent is \"\" - aborting\n", 0, 0, 0 );
640                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, 
641                                 "", "not allowed within namingContext", 
642                                 NULL, NULL );
643                 goto modrdn_return;
644         }
645
646         /*
647          * Check for children access to parent
648          */
649         e.e_attrs = NULL;
650         e.e_name = p_dn;
651         e.e_nname = p_ndn;
652         if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children, 
653                                 NULL, ACL_WRITE, NULL ) ) {
654                 Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
655                 res = LDAP_INSUFFICIENT_ACCESS;
656                 goto modrdn_return;
657         }
658
659         if ( newSuperior ) {
660                 /*
661                  * namingContext "" is not supported
662                  */
663                 if ( newSuperior->bv_len == 0 ) {
664                         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
665                                 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
666                         send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, 
667                                         "", "not allowed within namingContext", 
668                                         NULL, NULL );
669                         goto modrdn_return;
670                 }
671
672                 new_pdn = newSuperior;
673                 new_npdn = nnewSuperior;
674
675                 e.e_name = *new_pdn;
676                 e.e_nname = *new_npdn;
677
678                 /*
679                  * Check for children access to new parent
680                  */
681                 if ( !access_allowed( be, conn, op, &e, 
682                                         slap_schema.si_ad_children, 
683                                         NULL, ACL_WRITE, NULL ) ) {
684                         Debug( LDAP_DEBUG_TRACE, "no access to new parent\n", 
685                                         0, 0, 0 );
686                         res = LDAP_INSUFFICIENT_ACCESS;
687                         goto modrdn_return;
688                 }
689
690         } else {
691                 new_pdn = &p_dn;
692                 new_npdn = &p_ndn;
693         }
694
695         if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
696                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
697                         "newSuperior is equal to old parent - ignored\n",
698                         0, 0, 0 );
699                 newSuperior = NULL;
700         }
701
702         if ( newSuperior && dn_match( ndn, new_npdn ) ) {
703                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
704                         "newSuperior is equal to entry being moved "
705                         "- aborting\n", 0, 0, 0 );
706                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", 
707                                 NULL, NULL, NULL );
708                 goto modrdn_return;
709         }
710
711         build_new_dn( &new_dn, new_pdn, newrdn ); 
712         if ( dnNormalize2( NULL, &new_dn, &new_ndn ) != LDAP_SUCCESS ) {
713                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
714                         "new dn is invalid ('%s') - aborting\n",
715                         new_dn.bv_val, 0, 0 );
716                 send_ldap_result( conn, op, LDAP_INVALID_DN_SYNTAX, "", 
717                                 NULL, NULL, NULL );
718                 goto modrdn_return;
719         }
720         
721         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): new entry dn is '%s'\n",
722                         new_dn.bv_val, 0, 0 );
723
724         res = backsql_dn2id( bi, &pe_id, dbh, &p_ndn );
725         if ( res != LDAP_SUCCESS ) {
726                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
727                         "could not lookup old parent entry id\n", 0, 0, 0 );
728                 send_ldap_result( conn, op, res, "", 
729                                 res == LDAP_OTHER ? "SQL-backend error" : "",
730                                 NULL, NULL );
731                 goto modrdn_return;
732         }
733
734         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
735                 "old parent entry id is %ld\n", pe_id.id, 0, 0 );
736
737         res = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
738         if ( res != LDAP_SUCCESS ) {
739                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
740                         "could not lookup new parent entry id\n", 0, 0, 0 );
741                 send_ldap_result( conn, op, res, "",
742                                 res == LDAP_OTHER ? "SQL-backend error" : "",
743                                 NULL, NULL );
744                 goto modrdn_return;
745         }
746         
747         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
748                 "new parent entry id is %ld\n", new_pid.id, 0, 0 );
749
750  
751         Debug(  LDAP_DEBUG_TRACE, "backsql_modrdn(): "
752                 "executing delentry_query\n", 0, 0, 0 );
753         SQLAllocStmt( dbh, &sth );
754         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
755                         0, 0, &e_id.id, 0, 0 );
756         rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
757         if ( rc != SQL_SUCCESS ) {
758                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
759                         "failed to delete record from ldap_entries\n",
760                         0, 0, 0 );
761                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
762                 send_ldap_result( conn, op, LDAP_OTHER, "",
763                                 "SQL-backend error", NULL, NULL );
764                 goto modrdn_return;
765         }
766
767         SQLFreeStmt( sth, SQL_RESET_PARAMS );
768
769         Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
770                 "executing insentry_query\n", 0, 0, 0 );
771         backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
772         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
773                         0, 0, &e_id.oc_id, 0, 0 );
774         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
775                         0, 0, &new_pid.id, 0, 0 );
776         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
777                         0, 0, &e_id.keyval, 0, 0 );
778         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
779         if ( rc != SQL_SUCCESS ) {
780                 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
781                         "could not insert ldap_entries record\n", 0, 0, 0 );
782                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
783                 send_ldap_result( conn, op, LDAP_OTHER, "",
784                                 "SQL-backend error", NULL, NULL );
785                 goto modrdn_return;
786         }
787
788         /*
789          * Get attribute type and attribute value of our new rdn,
790          * we will need to add that to our new entry
791          */
792         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text, 
793                                 LDAP_DN_FORMAT_LDAP ) ) {
794 #ifdef NEW_LOGGING
795                 LDAP_LOG ( OPERATION, ERR, 
796                         "backsql_modrdn: can't figure out "
797                         "type(s)/values(s) of newrdn\n", 
798                         0, 0, 0 );
799 #else
800                 Debug( LDAP_DEBUG_TRACE,
801                         "backsql_modrdn: can't figure out "
802                         "type(s)/values(s) of newrdn\n", 
803                         0, 0, 0 );
804 #endif
805                 rc = LDAP_INVALID_DN_SYNTAX;
806                 goto modrdn_return;
807         }
808
809 #ifdef NEW_LOGGING
810         LDAP_LOG ( OPERATION, RESULTS, 
811                 "backsql_modrdn: new_rdn_type=\"%s\", "
812                 "new_rdn_val=\"%s\"\n",
813                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
814                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
815 #else
816         Debug( LDAP_DEBUG_TRACE,
817                 "backsql_modrdn: new_rdn_type=\"%s\", "
818                 "new_rdn_val=\"%s\"\n",
819                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
820                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
821 #endif
822
823         if ( deleteoldrdn ) {
824                 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
825                         LDAP_DN_FORMAT_LDAP ) ) {
826 #ifdef NEW_LOGGING
827                         LDAP_LOG ( OPERATION, ERR, 
828                                 "backsql_modrdn: can't figure out "
829                                 "type(s)/values(s) of old_rdn\n", 
830                                 0, 0, 0 );
831 #else
832                         Debug( LDAP_DEBUG_TRACE,
833                                 "backsql_modrdn: can't figure out "
834                                 "the old_rdn type(s)/value(s)\n", 
835                                 0, 0, 0 );
836 #endif
837                         rc = LDAP_OTHER;
838                         goto modrdn_return;             
839                 }
840         }
841
842         e.e_name = new_dn;
843         e.e_nname = new_ndn;
844         res = slap_modrdn2mods( be, conn, op, &e, old_rdn, new_rdn, 
845                         deleteoldrdn, &mod );
846         if ( res != LDAP_SUCCESS ) {
847                 goto modrdn_return;
848         }
849
850         if ( !acl_check_modlist( be, conn, op, &e, mod )) {
851                 res = LDAP_INSUFFICIENT_ACCESS;
852                 goto modrdn_return;
853         }
854
855         oc = backsql_id2oc( bi, e_id.oc_id );
856         res = backsql_modify_internal( bi, dbh, oc, &e_id, mod, &text );
857
858         if ( res == LDAP_SUCCESS ) {
859
860                 /*
861                  * Commit only if all operations succeed
862                  *
863                  * FIXME: backsql_modify_internal() does not fail 
864                  * if add/delete operations are not available, or
865                  * if a multiple value add actually results in a replace, 
866                  * or if a single operation on an attribute fails for any
867                  * reason
868                  */
869                 SQLTransact( SQL_NULL_HENV, dbh,
870                                 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
871         }
872
873 modrdn_return:
874         SQLFreeStmt( sth, SQL_DROP );
875
876         if ( new_dn.bv_val ) {
877                 ch_free( new_dn.bv_val );
878         }
879         
880         if ( new_ndn.bv_val ) {
881                 ch_free( new_ndn.bv_val );
882         }
883         
884         /* LDAP v2 supporting correct attribute handling. */
885         if ( new_rdn != NULL ) {
886                 ldap_rdnfree( new_rdn );
887         }
888         if ( old_rdn != NULL ) {
889                 ldap_rdnfree( old_rdn );
890         }
891         if( mod != NULL ) {
892                 Modifications *tmp;
893                 for (; mod; mod=tmp ) {
894                         tmp = mod->sml_next;
895                         free( mod );
896                 }
897         }
898
899         send_ldap_result( conn, op, res, "", text, NULL, NULL );
900
901         Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
902         return 0;
903 }
904
905 int
906 backsql_add(
907         BackendDB       *be,
908         Connection      *conn,
909         Operation       *op,
910         Entry           *e )
911 {
912         backsql_info            *bi = (backsql_info*)be->be_private;
913         SQLHDBC                 dbh;
914         SQLHSTMT                sth;
915         unsigned long           new_keyval = 0;
916         long                    i;
917         RETCODE                 rc;
918         backsql_oc_map_rec      *oc = NULL;
919         backsql_at_map_rec      *at_rec = NULL;
920         backsql_entryID         e_id, parent_id;
921         Entry                   p;
922         int                     res;
923         Attribute               *at;
924         struct berval           *at_val;
925         struct berval           pdn;
926         /* first parameter #, parameter order */
927         SQLUSMALLINT            pno, po;
928         /* procedure return code */
929         int                     prc;
930
931         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n",
932                         e->e_name.bv_val, 0, 0 );
933
934         for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
935                 if ( at->a_desc == slap_schema.si_ad_objectClass ) {
936                         if ( global_schemacheck ) {
937                                 const char      *text = NULL;
938                                 char            textbuf[ 1024 ];
939                                 size_t          textlen = sizeof( textbuf );
940                                 struct berval   soc;
941
942                                 int rc = structural_class( at->a_vals, &soc, 
943                                                 NULL, &text, textbuf, textlen );
944                                 if ( rc != LDAP_SUCCESS ) {
945                                         break;
946                                 }
947                                 oc = backsql_name2oc( bi, &soc );
948
949                         } else {
950
951                                 /*
952                                  * FIXME: only the objectClass provided first
953                                  * is considered when creating a new entry
954                                  */
955                                 oc = backsql_name2oc( bi, &at->a_vals[ 0 ] );
956                         }
957                         break;
958                 }
959         }
960
961         if ( oc == NULL ) {
962                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
963                         "cannot determine objectclass of entry -- aborting\n",
964                         0, 0, 0 );
965                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
966                                 "operation not permitted within namingContext",
967                                 NULL, NULL );
968                 return 1;
969         }
970
971         if ( oc->create_proc == NULL ) {
972                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
973                         "create procedure is not defined for this objectclass "
974                         "- aborting\n", 0, 0, 0 );
975                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
976                                 "operation not permitted within namingContext",
977                                 NULL, NULL );
978                 return 1;
979
980         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
981                         && oc->create_keyval == NULL ) {
982                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
983                         "create procedure needs select, but none is defined"
984                         "- aborting\n", 0, 0, 0 );
985                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
986                                 "operation not permitted within namingContext",
987                                 NULL, NULL );
988                 return 1;
989         }
990
991         prc = backsql_get_db_conn( be, conn, &dbh );
992         if ( prc != LDAP_SUCCESS ) {
993                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
994                         "could not get connection handle - exiting\n", 
995                         0, 0, 0 );
996                 send_ldap_result( conn, op, prc, "",
997                                 prc == LDAP_OTHER ?  "SQL-backend error" : "",
998                                 NULL, NULL );
999                 return 1;
1000         }
1001
1002         /*
1003          * Check if entry exists
1004          */
1005         res = backsql_dn2id( bi, &e_id, dbh, &e->e_name );
1006         if ( res == LDAP_SUCCESS ) {
1007                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1008                         "entry '%s' exists\n",
1009                         e->e_name.bv_val, 0, 0 );
1010                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", 
1011                                 NULL, NULL, NULL );
1012                 return 1;
1013         }
1014
1015         /*
1016          * Check if parent exists
1017          */
1018         dnParent( &e->e_name, &pdn );
1019         res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
1020         if ( res != LDAP_SUCCESS ) {
1021                 
1022                 /*
1023                  * NO SUCH OBJECT seems more appropriate
1024                  */
1025                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1026                         "could not lookup parent entry for new record '%s'\n",
1027                         pdn.bv_val, 0, 0 );
1028
1029                 if ( res != LDAP_NO_SUCH_OBJECT ) {
1030                         send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
1031                         return 1;
1032                 }
1033
1034                 /*
1035                  * Look for matched
1036                  */
1037                 while ( 1 ) {
1038                         struct berval   dn;
1039                         char            *matched = "";
1040
1041                         dn = pdn;
1042                         dnParent( &dn, &pdn );
1043
1044                         /*
1045                          * Empty DN ("") defaults to LDAP_SUCCESS
1046                          */
1047                         res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
1048                         switch ( res ) {
1049                         case LDAP_NO_SUCH_OBJECT:
1050                                 if ( pdn.bv_len > 0 ) {
1051                                         break;
1052                                 }
1053                                 /* fail over to next case */
1054                                 
1055                         case LDAP_SUCCESS:
1056                                 matched = pdn.bv_val;
1057                                 /* fail over to next case */
1058
1059                         default:
1060                                 send_ldap_result( conn, op, res, matched, 
1061                                                 NULL, NULL, NULL );
1062                                 return 1;
1063                         } 
1064                 }
1065         }
1066
1067         /*
1068          * create_proc is executed; if expect_return is set, then
1069          * an output parameter is bound, which should contain 
1070          * the id of the added row; otherwise the procedure
1071          * is expected to return the id as the first column of a select
1072          */
1073
1074         p.e_attrs = NULL;
1075         p.e_name = pdn;
1076         dnParent( &e->e_nname, &p.e_nname );
1077         if ( !access_allowed( be, conn, op, &p, slap_schema.si_ad_children,
1078                                 NULL, ACL_WRITE, NULL ) ) {
1079                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, 
1080                                 NULL, NULL, NULL, NULL );
1081                 return 1;
1082         }
1083
1084 #ifndef BACKSQL_REALLOC_STMT
1085         rc = SQLAllocStmt( dbh, &sth );
1086 #else /* BACKSQL_REALLOC_STMT */
1087         rc = backsql_Prepare( dbh, &sth, oc->create_proc, 0 );
1088 #endif /* BACKSQL_REALLOC_STMT */
1089         if ( rc != SQL_SUCCESS ) {
1090                 send_ldap_result( conn, op, LDAP_OTHER, "",
1091                                 "SQL-backend error", NULL, NULL );
1092                 return 1;
1093         }
1094
1095         if ( BACKSQL_IS_ADD( oc->expect_return ) ) {
1096                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
1097                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1098         }
1099
1100         Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s'\n",
1101                 oc->create_proc, 0, 0 );
1102 #ifndef BACKSQL_REALLOC_STMT
1103         rc = SQLExecDirect( sth, oc->create_proc, SQL_NTS );
1104 #else /* BACKSQL_REALLOC_STMT */
1105         rc = SQLExecute( sth );
1106 #endif /* BACKSQL_REALLOC_STMT */
1107         if ( rc != SQL_SUCCESS ) {
1108                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1109                         "create_proc execution failed\n", 0, 0, 0 );
1110                 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1111                 SQLFreeStmt( sth, SQL_DROP );
1112                 send_ldap_result( conn, op, LDAP_OTHER, "",
1113                                 "SQL-backend error", NULL, NULL );
1114                 return 1;
1115         }
1116
1117         if ( !BACKSQL_IS_ADD( oc->expect_return ) ) {
1118                 SWORD           ncols;
1119                 SQLINTEGER      is_null;
1120
1121                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
1122 #ifndef BACKSQL_REALLOC_STMT
1123                         SQLFreeStmt( sth, SQL_RESET_PARAMS );
1124 #else /* BACKSQL_REALLOC_STMT */
1125                         SQLFreeStmt( sth, SQL_DROP );
1126                         rc = SQLAllocStmt( dbh, &sth );
1127                         if ( rc != SQL_SUCCESS ) {
1128                                 send_ldap_result( conn, op, LDAP_OTHER, "",
1129                                         "SQL-backend error", NULL, NULL );
1130                                 return 1;
1131                         }
1132 #endif /* BACKSQL_REALLOC_STMT */
1133
1134                         rc = SQLExecDirect( sth, oc->create_keyval, SQL_NTS );
1135                         if ( rc != SQL_SUCCESS ) {
1136                                 send_ldap_result( conn, op, LDAP_OTHER, "",
1137                                         "SQL-backend error", NULL, NULL );
1138                                 return 1;
1139                         }
1140                 }
1141
1142                 /*
1143                  * the query to know the id of the inserted entry
1144                  * must be embedded in the create procedure
1145                  */
1146                 rc = SQLNumResultCols( sth, &ncols );
1147                 if ( rc != SQL_SUCCESS ) {
1148                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1149                                 "create_proc result evaluation failed\n",
1150                                 0, 0, 0 );
1151                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1152                         SQLFreeStmt( sth, SQL_DROP );
1153                         send_ldap_result( conn, op, LDAP_OTHER, "",
1154                                         "SQL-backend error", NULL, NULL );
1155                         return 1;
1156
1157                 } else if ( ncols != 1 ) {
1158                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1159                                 "create_proc result is bogus (ncols=%d)\n",
1160                                 ncols, 0, 0 );
1161                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
1162                         SQLFreeStmt( sth, SQL_DROP );
1163                         send_ldap_result( conn, op, LDAP_OTHER, "",
1164                                         "SQL-backend error", NULL, NULL );
1165                         return 1;
1166                 }
1167
1168 #if 0
1169                 {
1170                         SQLCHAR         colname[ 64 ];
1171                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
1172                         UDWORD          col_prec;
1173
1174                         /*
1175                          * FIXME: check whether col_type is compatible,
1176                          * if it can be null and so on ...
1177                          */
1178                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
1179                                         &colname[ 0 ], 
1180                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
1181                                         &name_len, &col_type,
1182                                         &col_prec, &col_scale, &col_null );
1183                 }
1184 #endif
1185
1186                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
1187                                 (SQLPOINTER)&new_keyval, 
1188                                 (SQLINTEGER)sizeof( new_keyval ), 
1189                                 &is_null );
1190
1191                 rc = SQLFetch( sth );
1192
1193 #if 0
1194                 /*
1195                  * FIXME: what does is_null mean?
1196                  */
1197                 if ( is_null ) {
1198                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1199                                 "create_proc result is null\n",
1200                                 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 #endif
1208         }
1209
1210 #ifndef BACKSQL_REALLOC_STMT
1211         SQLFreeStmt( sth, SQL_RESET_PARAMS );
1212 #else /* BACKSQL_REALLOC_STMT */
1213         SQLFreeStmt( sth, SQL_DROP );
1214 #endif /* BACKSQL_REALLOC_STMT */
1215
1216         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1217                 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
1218
1219         for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
1220                 SQLUSMALLINT    currpos;
1221
1222                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1223                         "adding attribute '%s'\n", 
1224                         at->a_desc->ad_cname.bv_val, 0, 0 );
1225
1226                 /*
1227                  * Skip:
1228                  * - the first occurrence of objectClass, which is used
1229                  *   to determine how to bulid the SQL entry (FIXME ?!?)
1230                  * - operational attributes
1231                  *   empty attributes (FIXME ?!?)
1232                  */
1233                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
1234                         continue;
1235                 }
1236
1237                 at_rec = backsql_ad2at( oc, at->a_desc ); 
1238   
1239                 if ( at_rec == NULL ) {
1240                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1241                                 "attribute '%s' is not registered "
1242                                 "in objectclass '%s'\n",
1243                                 at->a_desc->ad_cname.bv_val,
1244                                 BACKSQL_OC_NAME( oc ), 0 );
1245
1246                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1247                                 send_ldap_result( conn, op, 
1248                                                 LDAP_UNWILLING_TO_PERFORM, "",
1249                                                 "operation not permitted "
1250                                                 "within namingContext",
1251                                                 NULL, NULL );
1252                                 return 1;
1253                         }
1254
1255                         continue;
1256                 }
1257                 
1258                 if ( at_rec->add_proc == NULL ) {
1259                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1260                                 "add procedure is not defined "
1261                                 "for attribute '%s'\n",
1262                                 at->a_desc->ad_cname.bv_val, 0, 0 );
1263
1264                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1265                                 send_ldap_result( conn, op, 
1266                                                 LDAP_UNWILLING_TO_PERFORM, "",
1267                                                 "operation not permitted "
1268                                                 "within namingContext",
1269                                                 NULL, NULL );
1270                                 return 1;
1271                         }
1272
1273                         continue;
1274                 }
1275
1276 #ifdef BACKSQL_REALLOC_STMT
1277                 rc = backsql_Prepare( dbh, &sth, at_rec->add_proc, 0 );
1278                 if ( rc != SQL_SUCCESS ) {
1279
1280                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1281                                 send_ldap_result( conn, op, 
1282                                                 LDAP_OTHER, "",
1283                                                 "SQL-backend error",
1284                                                 NULL, NULL );
1285                                 return 1;
1286                         }
1287
1288                         continue;
1289                 }
1290 #endif /* BACKSQL_REALLOC_STMT */
1291
1292                 if ( BACKSQL_IS_ADD( at_rec->expect_return ) ) {
1293                         pno = 1;
1294                         SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
1295                                         SQL_C_ULONG, SQL_INTEGER,
1296                                         0, 0, &prc, 0, 0 );
1297                 } else {
1298                         pno = 0;
1299                 }
1300
1301                 po = ( BACKSQL_IS_ADD( at_rec->param_order ) ) > 0;
1302                 currpos = pno + 1 + po;
1303                 SQLBindParameter( sth, currpos,
1304                                 SQL_PARAM_INPUT, SQL_C_ULONG,
1305                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
1306                 currpos = pno + 2 - po;
1307
1308                 for ( i = 0, at_val = &at->a_vals[ i ];
1309                                 at_val->bv_val != NULL;
1310                                 i++, at_val = &at->a_vals[ i ] ) {
1311
1312                         /*
1313                          * Do not deal with the objectClass that is used
1314                          * to build the entry
1315                          */
1316                         if ( at->a_desc == slap_schema.si_ad_objectClass ) {
1317                                 if ( bvmatch( at_val, &oc->oc->soc_cname ) ) {
1318                                         continue;
1319                                 }
1320                         }
1321
1322                         /*
1323                          * check for syntax needed here 
1324                          * maybe need binary bind?
1325                          */
1326
1327                         backsql_BindParamStr( sth, currpos,
1328                                         at_val->bv_val, at_val->bv_len + 1 );
1329 #ifdef SECURITY_PARANOID
1330                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1331                                 "executing '%s', id=%ld\n", 
1332                                 at_rec->add_proc, new_keyval, 0 );
1333 #else
1334                         Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1335                                 "executing '%s' with val='%s', id=%ld\n", 
1336                                 at_rec->add_proc, at_val->bv_val, new_keyval );
1337 #endif
1338 #ifndef BACKSQL_REALLOC_STMT
1339                         rc = SQLExecDirect( sth, at_rec->add_proc, SQL_NTS );
1340 #else /* BACKSQL_REALLOC_STMT */
1341                         rc = SQLExecute( sth );
1342 #endif /* BACKSQL_REALLOC_STMT */
1343                         if ( rc != SQL_SUCCESS ) {
1344                                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1345                                         "add_proc execution failed\n", 
1346                                         0, 0, 0 );
1347                                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1348
1349                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1350                                         send_ldap_result( conn, op, 
1351                                                         LDAP_OTHER, "",
1352                                                         "SQL-backend error",
1353                                                         NULL, NULL );
1354                                         return 1;
1355                                 }
1356                         }
1357                 }
1358 #ifndef BACKSQL_REALLOC_STMT
1359                 SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
1360 #else /* BACKSQL_REALLOC_STMT */
1361                 SQLFreeStmt( sth, SQL_DROP );
1362 #endif /* BACKSQL_REALLOC_STMT */
1363         }
1364
1365 #ifdef BACKSQL_REALLOC_STMT
1366         rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1367         if ( rc != SQL_SUCCESS ) {
1368                 send_ldap_result( conn, op, LDAP_OTHER, "",
1369                                 "SQL-backend error", NULL, NULL );
1370                 return 1;
1371         }
1372 #endif /* BACKSQL_REALLOC_STMT */
1373         
1374         backsql_BindParamStr( sth, 1, e->e_name.bv_val, BACKSQL_MAX_DN_LEN );
1375         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1376                         0, 0, &oc->id, 0, 0 );
1377         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1378                         0, 0, &parent_id.id, 0, 0 );
1379         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1380                         0, 0, &new_keyval, 0, 0 );
1381
1382         Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s' for dn '%s'\n",
1383                         bi->insentry_query, e->e_name.bv_val, 0 );
1384         Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, "
1385                         "keyval=%ld\n", oc->id, parent_id.id, new_keyval );
1386 #ifndef BACKSQL_REALLOC_STMT
1387         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1388 #else /* BACKSQL_REALLOC_STMT */
1389         rc = SQLExecute( sth );
1390 #endif /* BACKSQL_REALLOC_STMT */
1391         if ( rc != SQL_SUCCESS ) {
1392                 Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
1393                         "could not insert ldap_entries record\n", 0, 0, 0 );
1394                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1395                 
1396                 /*
1397                  * execute delete_proc to delete data added !!!
1398                  */
1399                 SQLFreeStmt( sth, SQL_DROP );
1400                 send_ldap_result( conn, op, LDAP_OTHER, "", 
1401                                 "SQL-backend error", NULL, NULL );
1402                 return 1;
1403         }
1404         
1405         SQLFreeStmt( sth, SQL_DROP );
1406
1407         /*
1408          * Commit only if all operations succeed
1409          *
1410          * FIXME: backsql_add() does not fail if add operations 
1411          * are not available for some attributes, or if
1412          * a multiple value add actually results in a replace, 
1413          * or if a single operation on an attribute fails 
1414          * for any reason
1415          */
1416         SQLTransact( SQL_NULL_HENV, dbh, 
1417                                 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1418
1419         send_ldap_result( conn, op, LDAP_SUCCESS, "",
1420                         NULL, NULL, NULL );
1421         return 0;
1422 }
1423
1424 int
1425 backsql_delete(
1426         BackendDB       *be,
1427         Connection      *conn,
1428         Operation       *op,
1429         struct berval   *dn,
1430         struct berval   *ndn )
1431 {
1432         backsql_info            *bi = (backsql_info*)be->be_private;
1433         SQLHDBC                 dbh;
1434         SQLHSTMT                sth;
1435         RETCODE                 rc;
1436         backsql_oc_map_rec      *oc = NULL;
1437         backsql_entryID         e_id;
1438         Entry                   e;
1439         int                     res;
1440         /* first parameter no */
1441         SQLUSMALLINT            pno;
1442
1443         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
1444                         ndn->bv_val, 0, 0 );
1445
1446         dnParent( dn, &e.e_name );
1447         dnParent( ndn, &e.e_nname );
1448         e.e_attrs = NULL;
1449
1450         /* check parent for "children" acl */
1451         if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children, 
1452                         NULL, ACL_WRITE, NULL ) ) {
1453                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1454                         "no write access to parent\n", 
1455                         0, 0, 0 );
1456                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, 
1457                                 "", NULL, NULL, NULL );
1458                 return 1;
1459
1460         }
1461         
1462         res = backsql_get_db_conn( be, conn, &dbh );
1463         if ( res != LDAP_SUCCESS ) {
1464                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1465                         "could not get connection handle - exiting\n", 
1466                         0, 0, 0 );
1467                 send_ldap_result( conn, op, res, "", 
1468                                 res == LDAP_OTHER ? "SQL-backend error" : "",
1469                                 NULL, NULL );
1470                 return 1;
1471         }
1472         
1473         res = backsql_dn2id( bi, &e_id, dbh, ndn );
1474         if ( res != LDAP_SUCCESS ) {
1475                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1476                         "could not lookup entry id\n", 0, 0, 0 );
1477                 send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
1478                 return 1;
1479         }
1480
1481         res = backsql_has_children( bi, dbh, ndn );
1482         switch ( res ) {
1483         case LDAP_COMPARE_TRUE:
1484                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1485                         "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
1486                 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
1487                                 NULL, "subtree delete not supported",
1488                                 NULL, NULL );
1489                 return 1;
1490
1491         case LDAP_COMPARE_FALSE:
1492                 break;
1493
1494         default:
1495                 send_ldap_result( conn, op, res, NULL, NULL, NULL, NULL );
1496                 return 1;
1497         }
1498
1499         oc = backsql_id2oc( bi, e_id.oc_id );
1500         if ( oc == NULL ) {
1501                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1502                         "cannot determine objectclass of entry "
1503                         "-- aborting\n", 0, 0, 0 );
1504                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
1505                                 "operation not permitted within namingContext",
1506                                 NULL, NULL );
1507                 return 1;
1508         }
1509
1510         if ( oc->delete_proc == NULL ) {
1511                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1512                         "delete procedure is not defined "
1513                         "for this objectclass - aborting\n", 0, 0, 0 );
1514                 send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
1515                                 "operation not permitted within namingContext",
1516                                 NULL, NULL );
1517                 return 1;
1518         }
1519
1520         SQLAllocStmt( dbh, &sth );
1521         if ( BACKSQL_IS_DEL( oc->expect_return ) ) {
1522                 pno = 1;
1523                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
1524                                 SQL_INTEGER, 0, 0, &rc, 0, 0 );
1525         } else {
1526                 pno = 0;
1527         }
1528
1529         SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT, 
1530                         SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 );
1531
1532         Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n",
1533                         oc->delete_proc, 0, 0 );
1534         rc = SQLExecDirect( sth, oc->delete_proc, SQL_NTS );
1535         if ( rc != SQL_SUCCESS ) {
1536                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1537                         "delete_proc execution failed\n", 0, 0, 0 );
1538                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1539                 SQLFreeStmt( sth, SQL_DROP );
1540                 send_ldap_result( conn, op, LDAP_OTHER, "",
1541                                 "SQL-backend error", NULL, NULL );
1542                 return 1;
1543         }
1544 #ifndef BACKSQL_REALLOC_STMT
1545         SQLFreeStmt( sth, SQL_RESET_PARAMS );
1546 #else /* BACKSQL_REALLOC_STMT */
1547         SQLFreeStmt( sth, SQL_DROP );
1548         SQLAllocStmt( dbh, &sth );
1549 #endif /* BACKSQL_REALLOC_STMT */
1550
1551         SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
1552                         0, 0, &e_id.id, 0, 0 );
1553         rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
1554         if ( rc != SQL_SUCCESS ) {
1555                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
1556                         "failed to delete record from ldap_entries\n", 
1557                         0, 0, 0 );
1558                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1559                 SQLFreeStmt( sth, SQL_DROP );
1560                 send_ldap_result( conn, op, LDAP_OTHER, "",
1561                                 "SQL-backend error", NULL, NULL );
1562                 return 1;
1563         }
1564         
1565         SQLFreeStmt( sth, SQL_DROP );
1566
1567         /*
1568          * Commit only if all operations succeed
1569          *
1570          * FIXME: backsql_add() does not fail if add operations 
1571          * are not available for some attributes, or if
1572          * a multiple value add actually results in a replace, 
1573          * or if a single operation on an attribute fails 
1574          * for any reason
1575          */
1576         SQLTransact( SQL_NULL_HENV, dbh, 
1577                                 op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1578
1579         send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
1580         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
1581         return 0;
1582 }
1583
1584 #endif /* SLAPD_SQL */
1585