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