]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/add.c
General improvements:
[openldap] / servers / slapd / back-sql / add.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2004 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Dmitry Kovalev for inclusion
18  * by OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #ifdef SLAPD_SQL
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "ldap_pvt.h"
31 #include "proto-sql.h"
32
33 /*
34  * Skip:
35  * - the first occurrence of objectClass, which is used
36  *   to determine how to build the SQL entry (FIXME ?!?)
37  * - operational attributes
38  *   empty attributes (FIXME ?!?)
39  */
40 #define backsql_attr_skip(ad,vals) \
41         ( \
42                 ( (ad) == slap_schema.si_ad_objectClass \
43                                 && (vals)[ 1 ].bv_val == NULL ) \
44                 || is_at_operational( (ad)->ad_type ) \
45                 || ( (vals)[ 0 ].bv_val == NULL ) \
46         )
47
48 int
49 backsql_modify_internal(
50         Operation               *op,
51         SlapReply               *rs,
52         SQLHDBC                 dbh, 
53         backsql_oc_map_rec      *oc,
54         backsql_entryID         *e_id,
55         Modifications           *modlist )
56 {
57         backsql_info    *bi = (backsql_info*)op->o_bd->be_private;
58         RETCODE         rc;
59         SQLHSTMT        sth;
60         Modifications   *ml;
61
62         Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
63                 "traversing modifications list\n", 0, 0, 0 );
64
65 #ifndef BACKSQL_REALLOC_STMT
66         SQLAllocStmt( dbh, &sth );
67 #endif /* BACKSQL_REALLOC_STMT */
68
69         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
70                 AttributeDescription    *ad;
71                 backsql_at_map_rec      *at = NULL;
72                 struct berval           *at_val;
73                 Modification            *c_mod;
74                 int                     i;
75                 /* first parameter no, parameter order */
76                 SQLUSMALLINT            pno, po;
77                 /* procedure return code */
78                 int                     prc;
79
80 #ifdef BACKSQL_REALLOC_STMT
81                 SQLAllocStmt( dbh, &sth );
82 #endif /* BACKSQL_REALLOC_STMT */
83
84                 c_mod = &ml->sml_mod;
85                 ad = c_mod->sm_desc;
86
87                 Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
88                         "modifying attribute \"%s\" according to "
89                         "mappings for objectClass \"%s\"\n",
90                         ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
91
92                 if ( backsql_attr_skip( ad, c_mod->sm_values ) ) {
93                         continue;
94                 }
95
96                 at = backsql_ad2at( oc, ad );
97                 if ( at == NULL ) {
98                         Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
99                                 "attribute \"%s\" is not registered "
100                                 "in objectClass \"%s\"\n",
101                                 ad->ad_cname.bv_val, oc, 0 );
102
103                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
104                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
105                                 rs->sr_text = "operation not permitted "
106                                         "within namingContext";
107                                 goto done;
108                         }
109
110                         continue;
111                 }
112   
113                 switch( c_mod->sm_op ) {
114                 case LDAP_MOD_REPLACE: {
115                         SQLHSTMT asth;
116                         BACKSQL_ROW_NTS row;
117                         
118                         Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
119                                 "replacing values for attribute \"%s\"\n",
120                                 at->bam_ad->ad_cname.bv_val, 0, 0 );
121
122                         if ( at->bam_add_proc == NULL ) {
123                                 Debug( LDAP_DEBUG_TRACE,
124                                         "   backsql_modify_internal(): "
125                                         "add procedure is not defined "
126                                         "for attribute \"%s\" "
127                                         "- unable to perform replacements\n",
128                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
129
130                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
131                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
132                                         rs->sr_text = "operation not permitted "
133                                                 "within namingContext";
134                                         goto done;
135                                 }
136
137                                 break;
138                         }
139
140                         if ( at->bam_delete_proc == NULL ) {
141                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
142                                         Debug( LDAP_DEBUG_TRACE,
143                                                 "   backsql_modify_internal(): "
144                                                 "delete procedure is not defined "
145                                                 "for attribute \"%s\"\n",
146                                                 at->bam_ad->ad_cname.bv_val, 0, 0 );
147
148                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
149                                         rs->sr_text = "operation not permitted "
150                                                 "within namingContext";
151                                         goto done;
152                                 }
153
154                                 Debug( LDAP_DEBUG_TRACE,
155                                         "   backsql_modify_internal(): "
156                                         "delete procedure is not defined "
157                                         "for attribute \"%s\" "
158                                         "- adding only\n",
159                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
160
161                                 goto add_only;
162                         }
163                         
164 del_all:
165                         rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
166                         if ( rc != SQL_SUCCESS ) {
167                                 Debug( LDAP_DEBUG_TRACE,
168                                         "   backsql_modify_internal(): "
169                                         "error preparing query\n", 0, 0, 0 );
170                                 backsql_PrintErrors( bi->db_env, dbh, 
171                                                 asth, rc );
172
173                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
174                                         rs->sr_err = LDAP_OTHER;
175                                         rs->sr_text = "SQL-backend error";
176                                         goto done;
177                                 }
178
179                                 break;
180                         }
181
182 #ifdef BACKSQL_ARBITRARY_KEY
183                         rc = backsql_BindParamStr( asth, 1,
184                                         e_id->eid_keyval.bv_val,
185                                         BACKSQL_MAX_KEY_LEN );
186 #else /* ! BACKSQL_ARBITRARY_KEY */
187                         rc = backsql_BindParamID( asth, 1, &e_id->eid_keyval );
188 #endif /* ! BACKSQL_ARBITRARY_KEY */
189                         if ( rc != SQL_SUCCESS ) {
190                                 Debug( LDAP_DEBUG_TRACE,
191                                         "   backsql_modify_internal(): "
192                                         "error binding key value parameter\n",
193                                         0, 0, 0 );
194                                 backsql_PrintErrors( bi->db_env, dbh, 
195                                                 asth, rc );
196                                 SQLFreeStmt( asth, SQL_DROP );
197
198                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
199                                         rs->sr_err = LDAP_OTHER;
200                                         rs->sr_text = "SQL-backend error";
201                                         goto done;
202                                 }
203
204                                 break;
205                         }
206                         
207                         rc = SQLExecute( asth );
208                         if ( !BACKSQL_SUCCESS( rc ) ) {
209                                 Debug( LDAP_DEBUG_TRACE,
210                                         "   backsql_modify_internal(): "
211                                         "error executing attribute query\n",
212                                         0, 0, 0 );
213                                 backsql_PrintErrors( bi->db_env, dbh, 
214                                                 asth, rc );
215                                 SQLFreeStmt( asth, SQL_DROP );
216
217                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
218                                         rs->sr_err = LDAP_OTHER;
219                                         rs->sr_text = "SQL-backend error";
220                                         goto done;
221                                 }
222
223                                 break;
224                         }
225
226                         backsql_BindRowAsStrings( asth, &row );
227                         rc = SQLFetch( asth );
228                         for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
229                                 for ( i = 0; i < row.ncols; i++ ) {
230                                         if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
231                                                 pno = 1;
232                                                 SQLBindParameter(sth, 1,
233                                                         SQL_PARAM_OUTPUT,
234                                                         SQL_C_ULONG,
235                                                         SQL_INTEGER,
236                                                         0, 0, &prc, 0, 0 );
237                                         } else {
238                                                 pno = 0;
239                                         }
240                                         po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
241 #ifdef BACKSQL_ARBITRARY_KEY
242                                         SQLBindParameter( sth, pno + 1 + po,
243                                                 SQL_PARAM_INPUT,
244                                                 SQL_C_CHAR, SQL_VARCHAR,
245                                                 0, 0, e_id->eid_keyval.bv_val, 
246                                                 0, 0 );
247 #else /* ! BACKSQL_ARBITRARY_KEY */
248                                         SQLBindParameter( sth, pno + 1 + po,
249                                                 SQL_PARAM_INPUT,
250                                                 SQL_C_ULONG, SQL_INTEGER,
251                                                 0, 0, &e_id->eid_keyval, 0, 0 );
252 #endif /* ! BACKSQL_ARBITRARY_KEY */
253
254                                         /*
255                                          * check for syntax needed here 
256                                          * maybe need binary bind?
257                                          */
258                                         SQLBindParameter(sth, pno + 2 - po,
259                                                 SQL_PARAM_INPUT,
260                                                 SQL_C_CHAR, SQL_CHAR,
261                                                 0, 0, row.cols[ i ],
262                                                 strlen( row.cols[ i ] ), 0 );
263                          
264                                         Debug( LDAP_DEBUG_TRACE, 
265                                                 "   backsql_modify_internal(): "
266                                                 "executing \"%s\"\n",
267                                                 at->bam_delete_proc, 0, 0 );
268                                         rc = SQLExecDirect( sth,
269                                                 at->bam_delete_proc, SQL_NTS );
270                                         if ( rc != SQL_SUCCESS ) {
271                                                 Debug( LDAP_DEBUG_TRACE,
272                                                         "   backsql_modify_internal(): "
273                                                         "delete_proc "
274                                                         "execution failed\n",
275                                                         0, 0, 0 );
276                                                 backsql_PrintErrors( bi->db_env,
277                                                                 dbh, sth, rc );
278
279                                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
280                                                         rs->sr_err = LDAP_OTHER;
281                                                         rs->sr_text = "SQL-backend error";
282                                                         goto done;
283                                                 }
284                                         }
285 #ifdef BACKSQL_REALLOC_STMT
286                                         SQLFreeStmt( sth, SQL_DROP );
287                                         SQLAllocStmt( dbh, &sth );
288 #endif /* BACKSQL_REALLOC_STMT */
289                                 }
290                         }
291                         backsql_FreeRow( &row );
292                         SQLFreeStmt( asth, SQL_DROP );
293                 }
294
295                 /*
296                  * PASSTHROUGH - to add new attributes -- do NOT add break
297                  */
298                 case LDAP_MOD_ADD:
299                 case SLAP_MOD_SOFTADD:
300 add_only:;
301                         if ( at->bam_add_proc == NULL ) {
302                                 Debug( LDAP_DEBUG_TRACE,
303                                         "   backsql_modify_internal(): "
304                                         "add procedure is not defined "
305                                         "for attribute \"%s\"\n",
306                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
307
308                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
309                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
310                                         rs->sr_text = "operation not permitted "
311                                                 "within namingContext";
312                                         goto done;
313                                 }
314
315                                 break;
316                         }
317                         
318                         Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
319                                 "adding new values for attribute \"%s\"\n",
320                                 at->bam_ad->ad_cname.bv_val, 0, 0 );
321                         for ( i = 0, at_val = c_mod->sm_values;
322                                         at_val->bv_val != NULL; 
323                                         i++, at_val++ ) {
324                                 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
325                                         pno = 1;
326                                         SQLBindParameter( sth, 1,
327                                                 SQL_PARAM_OUTPUT,
328                                                 SQL_C_ULONG, SQL_INTEGER,
329                                                 0, 0, &prc, 0, 0);
330                                 } else {
331                                         pno = 0;
332                                 }
333                                 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
334 #ifdef BACKSQL_ARBITRARY_KEY
335                                 SQLBindParameter( sth, pno + 1 + po,
336                                         SQL_PARAM_INPUT, 
337                                         SQL_C_CHAR, SQL_VARCHAR,
338                                         0, 0, e_id->eid_keyval.bv_val, 0, 0 );
339 #else /* ! BACKSQL_ARBITRARY_KEY */
340                                 SQLBindParameter( sth, pno + 1 + po,
341                                         SQL_PARAM_INPUT, 
342                                         SQL_C_ULONG, SQL_INTEGER,
343                                         0, 0, &e_id->eid_keyval, 0, 0 );
344 #endif /* ! BACKSQL_ARBITRARY_KEY */
345
346                                 /*
347                                  * check for syntax needed here
348                                  * maybe need binary bind?
349                                  */
350                                 SQLBindParameter( sth, pno + 2 - po,
351                                         SQL_PARAM_INPUT,
352                                         SQL_C_CHAR, SQL_CHAR,
353                                         0, 0, at_val->bv_val, 
354                                         at_val->bv_len, 0 );
355
356                                 Debug( LDAP_DEBUG_TRACE,
357                                         "   backsql_modify_internal(): "
358                                         "executing \"%s\"\n", 
359                                         at->bam_add_proc, 0, 0 );
360                                 rc = SQLExecDirect( sth, at->bam_add_proc, 
361                                                 SQL_NTS );
362                                 if ( rc != SQL_SUCCESS ) {
363                                         Debug( LDAP_DEBUG_TRACE,
364                                                 "   backsql_modify_internal(): "
365                                                 "add_proc execution failed\n",
366                                                 0, 0, 0 );
367                                         backsql_PrintErrors( bi->db_env,
368                                                         dbh, sth, rc );
369
370                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
371                                                 rs->sr_err = LDAP_OTHER;
372                                                 rs->sr_text = "SQL-backend error";
373                                                 goto done;
374                                         }
375                                 }
376 #ifdef BACKSQL_REALLOC_STMT
377                                 SQLFreeStmt( sth, SQL_DROP );
378                                 SQLAllocStmt( dbh, &sth );
379 #endif /* BACKSQL_REALLOC_STMT */
380                         }
381                         break;
382                         
383                 case LDAP_MOD_DELETE:
384                         if ( at->bam_delete_proc == NULL ) {
385                                 Debug( LDAP_DEBUG_TRACE,
386                                         "   backsql_modify_internal(): "
387                                         "delete procedure is not defined "
388                                         "for attribute \"%s\"\n",
389                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
390
391                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
392                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
393                                         rs->sr_text = "operation not permitted "
394                                                 "within namingContext";
395                                         goto done;
396                                 }
397
398                                 break;
399                         }
400
401                         if ( c_mod->sm_values == NULL ) {
402                                 Debug( LDAP_DEBUG_TRACE,
403                                         "   backsql_modify_internal(): "
404                                         "no values given to delete "
405                                         "for attribute \"%s\" "
406                                         "-- deleting all values\n",
407                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
408                                 goto del_all;
409                         }
410
411                         Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
412                                 "deleting values for attribute \"%s\"\n",
413                                 at->bam_ad->ad_cname.bv_val, 0, 0 );
414
415                         for ( i = 0, at_val = c_mod->sm_values;
416                                         at_val->bv_val != NULL;
417                                         i++, at_val++ ) {
418                                 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
419                                         pno = 1;
420                                         SQLBindParameter( sth, 1,
421                                                 SQL_PARAM_OUTPUT,
422                                                 SQL_C_ULONG, SQL_INTEGER,
423                                                 0, 0, &prc, 0, 0 );
424                                 } else {
425                                         pno = 0;
426                                 }
427                                 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
428 #ifdef BACKSQL_ARBITRARY_KEY
429                                 SQLBindParameter( sth, pno + 1 + po,
430                                         SQL_PARAM_INPUT, 
431                                         SQL_C_CHAR, SQL_VARCHAR,
432                                         0, 0, e_id->eid_keyval.bv_val, 0, 0 );
433 #else /* ! BACKSQL_ARBITRARY_KEY */
434                                 SQLBindParameter( sth, pno + 1 + po,
435                                         SQL_PARAM_INPUT, 
436                                         SQL_C_ULONG, SQL_INTEGER,
437                                         0, 0, &e_id->eid_keyval, 0, 0 );
438 #endif /* ! BACKSQL_ARBITRARY_KEY */
439
440                                 /*
441                                  * check for syntax needed here 
442                                  * maybe need binary bind?
443                                  */
444                                 SQLBindParameter( sth, pno + 2 - po,
445                                         SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
446                                         0, 0, at_val->bv_val, 
447                                         at_val->bv_len, 0 );
448
449                                 Debug( LDAP_DEBUG_TRACE,
450                                         "   backsql_modify_internal(): "
451                                         "executing \"%s\"\n", 
452                                         at->bam_delete_proc, 0, 0 );
453                                 rc = SQLExecDirect( sth, at->bam_delete_proc,
454                                                 SQL_NTS );
455                                 if ( rc != SQL_SUCCESS ) {
456                                         Debug( LDAP_DEBUG_TRACE,
457                                                 "   backsql_modify_internal(): "
458                                                 "delete_proc execution "
459                                                 "failed\n", 0, 0, 0 );
460                                         backsql_PrintErrors( bi->db_env,
461                                                         dbh, sth, rc );
462
463                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
464                                                 rs->sr_err = LDAP_OTHER;
465                                                 rs->sr_text = "SQL-backend error";
466                                                 goto done;
467                                         }
468                                 }
469 #ifdef BACKSQL_REALLOC_STMT
470                                 SQLFreeStmt( sth, SQL_DROP );
471                                 SQLAllocStmt( dbh, &sth );
472 #endif /* BACKSQL_REALLOC_STMT */
473                         }
474                         break;
475                 }
476 #ifndef BACKSQL_REALLOC_STMT
477                 SQLFreeStmt( sth, SQL_RESET_PARAMS );
478 #else /* BACKSQL_REALLOC_STMT */
479                 SQLFreeStmt( sth, SQL_DROP );
480 #endif /* BACKSQL_REALLOC_STMT */
481         }
482
483 done:;
484         
485 #ifndef BACKSQL_REALLOC_STMT
486         SQLFreeStmt( sth, SQL_DROP );
487 #endif /* BACKSQL_REALLOC_STMT */
488
489         Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
490                 rs->sr_err, rs->sr_text ? ": " : "",
491                 rs->sr_text ? rs->sr_text : "" );
492
493         /*
494          * FIXME: should fail in case one change fails?
495          */
496         return rs->sr_err;
497 }
498
499 int
500 backsql_add( Operation *op, SlapReply *rs )
501 {
502         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
503         SQLHDBC                 dbh;
504         SQLHSTMT                sth;
505         unsigned long           new_keyval = 0;
506         long                    i;
507         RETCODE                 rc;
508         backsql_oc_map_rec      *oc = NULL;
509         backsql_at_map_rec      *at_rec = NULL;
510         backsql_entryID         e_id, parent_id;
511         Entry                   p;
512         Attribute               *at;
513         struct berval           *at_val;
514         struct berval           pdn;
515         /* first parameter #, parameter order */
516         SQLUSMALLINT            pno, po;
517         /* procedure return code */
518         int                     prc;
519
520         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry \"%s\"\n",
521                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
522
523         /* check schema */
524         if ( global_schemacheck ) {
525                 char            textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
526
527                 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
528                                 NULL,
529                                 &rs->sr_text, textbuf, sizeof( textbuf ) );
530                 if ( rs->sr_err != LDAP_SUCCESS ) {
531                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
532                                 "entry failed schema check -- aborting\n",
533                                 0, 0, 0 );
534                         goto done;
535                 }
536         }
537
538         /* search structural objectClass */
539         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
540                 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
541                         break;
542                 }
543         }
544
545         /* there must exist */
546         assert( at != NULL );
547
548         /* I guess we should play with sub/supertypes to find a suitable oc */
549         oc = backsql_name2oc( bi, &at->a_vals[0] );
550
551         if ( oc == NULL ) {
552                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
553                         "cannot determine objectclass of entry -- aborting\n",
554                         0, 0, 0 );
555                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
556                 rs->sr_text = "operation not permitted within namingContext";
557                 goto done;
558         }
559
560         if ( oc->bom_create_proc == NULL ) {
561                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
562                         "create procedure is not defined for this objectclass "
563                         "- aborting\n", 0, 0, 0 );
564                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
565                 rs->sr_text = "operation not permitted within namingContext";
566                 goto done;
567
568         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
569                         && oc->bom_create_keyval == NULL ) {
570                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
571                         "create procedure needs select procedure, "
572                         "but none is defined - aborting\n", 0, 0, 0 );
573                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
574                 rs->sr_text = "operation not permitted within namingContext";
575                 goto done;
576         }
577
578         rs->sr_err = backsql_get_db_conn( op, &dbh );
579         if ( rs->sr_err != LDAP_SUCCESS ) {
580                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
581                         "could not get connection handle - exiting\n", 
582                         0, 0, 0 );
583                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
584                         ?  "SQL-backend error" : NULL;
585                 goto done;
586         }
587
588         /*
589          * Check if entry exists
590          */
591         rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->oq_add.rs_e->e_name );
592         if ( rs->sr_err == LDAP_SUCCESS ) {
593                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
594                         "entry \"%s\" exists\n",
595                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
596                 rs->sr_err = LDAP_ALREADY_EXISTS;
597                 goto done;
598         }
599
600         /*
601          * Check if parent exists
602          */
603         dnParent( &op->oq_add.rs_e->e_name, &pdn );
604         rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
605         if ( rs->sr_err != LDAP_SUCCESS ) {
606                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
607                         "could not lookup parent entry for new record \"%s\"\n",
608                         pdn.bv_val, 0, 0 );
609
610                 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
611                         goto done;
612                 }
613
614                 /*
615                  * Look for matched
616                  */
617                 while ( 1 ) {
618                         struct berval   dn;
619                         char            *matched = NULL;
620
621                         dn = pdn;
622                         dnParent( &dn, &pdn );
623
624                         /*
625                          * Empty DN ("") defaults to LDAP_SUCCESS
626                          */
627                         rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn );
628                         switch ( rs->sr_err ) {
629                         case LDAP_NO_SUCH_OBJECT:
630                                 if ( pdn.bv_len > 0 ) {
631                                         break;
632                                 }
633                                 /* fail over to next case */
634                                 
635                         case LDAP_SUCCESS:
636                                 matched = pdn.bv_val;
637                                 /* fail over to next case */
638
639                         default:
640                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
641                                 rs->sr_matched = matched;
642                                 goto done;
643                         } 
644                 }
645         }
646
647         /*
648          * create_proc is executed; if expect_return is set, then
649          * an output parameter is bound, which should contain 
650          * the id of the added row; otherwise the procedure
651          * is expected to return the id as the first column of a select
652          */
653
654         p.e_attrs = NULL;
655         p.e_name = pdn;
656         dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
657         if ( !access_allowed( op, &p, slap_schema.si_ad_children,
658                                 NULL, ACL_WRITE, NULL ) ) {
659                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
660                 goto done;
661         }
662
663         rc = SQLAllocStmt( dbh, &sth );
664         if ( rc != SQL_SUCCESS ) {
665                 rs->sr_err = LDAP_OTHER;
666                 rs->sr_text = "SQL-backend error";
667                 goto done;
668         }
669
670         if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
671                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
672                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
673         }
674
675         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\"\n",
676                 oc->bom_create_proc, 0, 0 );
677         rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
678         if ( rc != SQL_SUCCESS ) {
679                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
680                         "create_proc execution failed\n", 0, 0, 0 );
681                 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
682                 SQLFreeStmt( sth, SQL_DROP );
683                 rs->sr_err = LDAP_OTHER;
684                 rs->sr_text = "SQL-backend error";
685                 goto done;
686         }
687         if ( op->o_noop ) {
688                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
689         }
690
691         if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
692                 SWORD           ncols;
693                 SQLINTEGER      value_len;
694
695                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
696 #ifndef BACKSQL_REALLOC_STMT
697                         SQLFreeStmt( sth, SQL_RESET_PARAMS );
698 #else /* BACKSQL_REALLOC_STMT */
699                         SQLFreeStmt( sth, SQL_DROP );
700                         rc = SQLAllocStmt( dbh, &sth );
701                         if ( rc != SQL_SUCCESS ) {
702                                 rs->sr_err = LDAP_OTHER;
703                                 rs->sr_text = "SQL-backend error";
704                                 goto done;
705                         }
706 #endif /* BACKSQL_REALLOC_STMT */
707
708                         rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
709                         if ( rc != SQL_SUCCESS ) {
710                                 rs->sr_err = LDAP_OTHER;
711                                 rs->sr_text = "SQL-backend error";
712                                 goto done;
713                         }
714                 }
715
716                 /*
717                  * the query to know the id of the inserted entry
718                  * must be embedded in the create procedure
719                  */
720                 rc = SQLNumResultCols( sth, &ncols );
721                 if ( rc != SQL_SUCCESS ) {
722                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
723                                 "create_proc result evaluation failed\n",
724                                 0, 0, 0 );
725                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
726                         SQLFreeStmt( sth, SQL_DROP );
727                         rs->sr_err = LDAP_OTHER;
728                         rs->sr_text = "SQL-backend error";
729                         goto done;
730
731                 } else if ( ncols != 1 ) {
732                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
733                                 "create_proc result is bogus (ncols=%d)\n",
734                                 ncols, 0, 0 );
735                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
736                         SQLFreeStmt( sth, SQL_DROP );
737                         rs->sr_err = LDAP_OTHER;
738                         rs->sr_text = "SQL-backend error";
739                         goto done;
740                 }
741
742 #if 0
743                 {
744                         SQLCHAR         colname[ 64 ];
745                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
746                         UDWORD          col_prec;
747
748                         /*
749                          * FIXME: check whether col_type is compatible,
750                          * if it can be null and so on ...
751                          */
752                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
753                                         &colname[ 0 ], 
754                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
755                                         &name_len, &col_type,
756                                         &col_prec, &col_scale, &col_null );
757                 }
758 #endif
759
760                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
761                                 (SQLPOINTER)&new_keyval, 
762                                 (SQLINTEGER)sizeof( new_keyval ), 
763                                 &value_len );
764
765                 rc = SQLFetch( sth );
766
767                 if ( value_len <= 0 ) {
768                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
769                                 "create_proc result is empty?\n",
770                                 0, 0, 0 );
771                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
772                         SQLFreeStmt( sth, SQL_DROP );
773                         rs->sr_err = LDAP_OTHER;
774                         rs->sr_text = "SQL-backend error";
775                         goto done;
776                 }
777         }
778
779 #ifndef BACKSQL_REALLOC_STMT
780         SQLFreeStmt( sth, SQL_RESET_PARAMS );
781 #else /* BACKSQL_REALLOC_STMT */
782         SQLFreeStmt( sth, SQL_DROP );
783 #endif /* BACKSQL_REALLOC_STMT */
784
785         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
786                 "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
787
788         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
789                 SQLUSMALLINT    currpos;
790
791                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
792                         "adding attribute \"%s\"\n", 
793                         at->a_desc->ad_cname.bv_val, 0, 0 );
794
795                 /*
796                  * Skip:
797                  * - the first occurrence of objectClass, which is used
798                  *   to determine how to bulid the SQL entry (FIXME ?!?)
799                  * - operational attributes
800                  *   empty attributes (FIXME ?!?)
801                  */
802                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
803                         continue;
804                 }
805
806                 at_rec = backsql_ad2at( oc, at->a_desc ); 
807   
808                 if ( at_rec == NULL ) {
809                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
810                                 "attribute \"%s\" is not registered "
811                                 "in objectclass \"%s\"\n",
812                                 at->a_desc->ad_cname.bv_val,
813                                 BACKSQL_OC_NAME( oc ), 0 );
814
815                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
816                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
817                                 rs->sr_text = "operation not permitted "
818                                         "within namingContext";
819                                 goto done;
820                         }
821
822                         continue;
823                 }
824                 
825                 if ( at_rec->bam_add_proc == NULL ) {
826                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
827                                 "add procedure is not defined "
828                                 "for attribute \"%s\"\n",
829                                 at->a_desc->ad_cname.bv_val, 0, 0 );
830
831                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
832                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
833                                 rs->sr_text = "operation not permitted "
834                                         "within namingContext";
835                                 goto done;
836                         }
837
838                         continue;
839                 }
840
841 #ifdef BACKSQL_REALLOC_STMT
842                 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
843                 if ( rc != SQL_SUCCESS ) {
844
845                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
846                                 rs->sr_err = LDAP_OTHER;
847                                 rs->sr_text = "SQL-backend error";
848                                 goto done;
849                         }
850
851                         continue;
852                 }
853 #endif /* BACKSQL_REALLOC_STMT */
854
855                 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
856                         pno = 1;
857                         SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
858                                         SQL_C_ULONG, SQL_INTEGER,
859                                         0, 0, &prc, 0, 0 );
860                 } else {
861                         pno = 0;
862                 }
863
864                 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
865                 currpos = pno + 1 + po;
866                 SQLBindParameter( sth, currpos,
867                                 SQL_PARAM_INPUT, SQL_C_ULONG,
868                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
869                 currpos = pno + 2 - po;
870
871                 for ( i = 0, at_val = &at->a_vals[ i ];
872                                 at_val->bv_val != NULL;
873                                 i++, at_val = &at->a_vals[ i ] ) {
874
875                         /*
876                          * Do not deal with the objectClass that is used
877                          * to build the entry
878                          */
879                         if ( at->a_desc == slap_schema.si_ad_objectClass ) {
880                                 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
881                                         continue;
882                                 }
883                         }
884
885                         /*
886                          * check for syntax needed here 
887                          * maybe need binary bind?
888                          */
889
890                         backsql_BindParamStr( sth, currpos,
891                                         at_val->bv_val, at_val->bv_len + 1 );
892 #ifdef SECURITY_PARANOID
893                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
894                                 "executing \"%s\", id=%ld\n", 
895                                 at_rec->bam_add_proc, new_keyval, 0 );
896 #else
897                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
898                                 "executing \"%s\" for val[%d], id=%ld\n", 
899                                 at_rec->bam_add_proc, i, new_keyval );
900 #endif
901 #ifndef BACKSQL_REALLOC_STMT
902                         rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
903 #else /* BACKSQL_REALLOC_STMT */
904                         rc = SQLExecute( sth );
905 #endif /* BACKSQL_REALLOC_STMT */
906                         if ( rc != SQL_SUCCESS ) {
907                                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
908                                         "add_proc execution failed\n", 
909                                         0, 0, 0 );
910                                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
911
912                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
913                                         rs->sr_err = LDAP_OTHER;
914                                         rs->sr_text = "SQL-backend error";
915                                         goto done;
916                                 }
917                         }
918                 }
919 #ifndef BACKSQL_REALLOC_STMT
920                 SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
921 #else /* BACKSQL_REALLOC_STMT */
922                 SQLFreeStmt( sth, SQL_DROP );
923 #endif /* BACKSQL_REALLOC_STMT */
924         }
925
926 #ifdef BACKSQL_REALLOC_STMT
927         rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
928         if ( rc != SQL_SUCCESS ) {
929                 rs->sr_err = LDAP_OTHER;
930                 rs->sr_text = "SQL-backend error";
931                 goto done;
932         }
933 #endif /* BACKSQL_REALLOC_STMT */
934         
935         backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
936                         BACKSQL_MAX_DN_LEN );
937         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
938                         0, 0, &oc->bom_id, 0, 0 );
939 #ifdef BACKSQL_ARBITRARY_KEY
940         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
941                         0, 0, parent_id.eid_id.bv_val, 0, 0 );
942 #else /* ! BACKSQL_ARBITRARY_KEY */
943         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
944                         0, 0, &parent_id.eid_id, 0, 0 );
945 #endif /* ! BACKSQL_ARBITRARY_KEY */
946         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
947                         0, 0, &new_keyval, 0, 0 );
948
949         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\" for dn \"%s\"\n",
950                         bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
951 #ifdef BACKSQL_ARBITRARY_KEY
952         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
953                         "parent_id=%s, keyval=%ld\n",
954                         oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
955 #else /* ! BACKSQL_ARBITRARY_KEY */
956         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
957                         "parent_id=%ld, keyval=%ld\n",
958                         oc->bom_id, parent_id.eid_id, new_keyval );
959 #endif /* ! BACKSQL_ARBITRARY_KEY */
960 #ifndef BACKSQL_REALLOC_STMT
961         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
962 #else /* BACKSQL_REALLOC_STMT */
963         rc = SQLExecute( sth );
964 #endif /* BACKSQL_REALLOC_STMT */
965         if ( rc != SQL_SUCCESS ) {
966                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
967                         "could not insert ldap_entries record\n", 0, 0, 0 );
968                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
969                 
970                 /*
971                  * execute delete_proc to delete data added !!!
972                  */
973                 SQLFreeStmt( sth, SQL_DROP );
974                 rs->sr_err = LDAP_OTHER;
975                 rs->sr_text = "SQL-backend error";
976                 goto done;
977         }
978         
979         SQLFreeStmt( sth, SQL_DROP );
980
981         /*
982          * Commit only if all operations succeed
983          */
984         SQLTransact( SQL_NULL_HENV, dbh, 
985                         op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
986
987         /*
988          * FIXME: NOOP does not work for add -- it works for all 
989          * the other operations, and I don't get the reason :(
990          * 
991          * hint: there might be some autocommit in Postgres
992          * so that when the unique id of the key table is
993          * automatically increased, there's no rollback.
994          * We might implement a "rollback" procedure consisting
995          * in deleting that row.
996          */
997
998 done:;
999         send_ldap_result( op, rs );
1000
1001         Debug( LDAP_DEBUG_TRACE, "<==backsql_add(): %d%s%s\n",
1002                         rs->sr_err,
1003                         rs->sr_text ? ": " : "",
1004                         rs->sr_text ? rs->sr_text : "" );
1005
1006         return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1007 }
1008
1009 #endif /* SLAPD_SQL */
1010