]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/add.c
handle referrals correctly; allow to add suffix entry; fix multiple values add bug...
[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
325                                 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
326                                 if ( rc != SQL_SUCCESS ) {
327                                         Debug( LDAP_DEBUG_TRACE,
328                                                 "   backsql_modify_internal(): "
329                                                 "error preparing add query\n", 
330                                                 0, 0, 0 );
331                                         backsql_PrintErrors( bi->db_env, dbh, sth, rc );
332
333                                         rs->sr_err = LDAP_OTHER;
334                                         rs->sr_text = "SQL-backend error";
335                                         goto done;
336                                 }
337
338                                 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
339                                         pno = 1;
340                                         SQLBindParameter( sth, 1,
341                                                 SQL_PARAM_OUTPUT,
342                                                 SQL_C_ULONG, SQL_INTEGER,
343                                                 0, 0, &prc, 0, 0);
344                                 } else {
345                                         pno = 0;
346                                 }
347                                 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
348 #ifdef BACKSQL_ARBITRARY_KEY
349                                 SQLBindParameter( sth, pno + 1 + po,
350                                         SQL_PARAM_INPUT, 
351                                         SQL_C_CHAR, SQL_VARCHAR,
352                                         0, 0, e_id->eid_keyval.bv_val, 0, 0 );
353 #else /* ! BACKSQL_ARBITRARY_KEY */
354                                 SQLBindParameter( sth, pno + 1 + po,
355                                         SQL_PARAM_INPUT, 
356                                         SQL_C_ULONG, SQL_INTEGER,
357                                         0, 0, &e_id->eid_keyval, 0, 0 );
358 #endif /* ! BACKSQL_ARBITRARY_KEY */
359
360                                 /*
361                                  * check for syntax needed here
362                                  * maybe need binary bind?
363                                  */
364                                 SQLBindParameter( sth, pno + 2 - po,
365                                         SQL_PARAM_INPUT,
366                                         SQL_C_CHAR, SQL_CHAR,
367                                         0, 0, at_val->bv_val, 
368                                         at_val->bv_len, 0 );
369
370                                 Debug( LDAP_DEBUG_TRACE,
371                                         "   backsql_modify_internal(): "
372                                         "executing \"%s\"\n", 
373                                         at->bam_add_proc, 0, 0 );
374                                 rc = SQLExecute( sth );
375                                 if ( rc != SQL_SUCCESS ) {
376                                         Debug( LDAP_DEBUG_TRACE,
377                                                 "   backsql_modify_internal(): "
378                                                 "add_proc execution failed\n",
379                                                 0, 0, 0 );
380                                         backsql_PrintErrors( bi->db_env,
381                                                         dbh, sth, rc );
382
383                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
384                                                 rs->sr_err = LDAP_OTHER;
385                                                 rs->sr_text = "SQL-backend error";
386                                                 goto done;
387                                         }
388                                 }
389 #ifdef BACKSQL_REALLOC_STMT
390                                 SQLFreeStmt( sth, SQL_DROP );
391                                 SQLAllocStmt( dbh, &sth );
392 #endif /* BACKSQL_REALLOC_STMT */
393                         }
394                         break;
395                         
396                 case LDAP_MOD_DELETE:
397                         if ( at->bam_delete_proc == NULL ) {
398                                 Debug( LDAP_DEBUG_TRACE,
399                                         "   backsql_modify_internal(): "
400                                         "delete procedure is not defined "
401                                         "for attribute \"%s\"\n",
402                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
403
404                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
405                                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
406                                         rs->sr_text = "operation not permitted "
407                                                 "within namingContext";
408                                         goto done;
409                                 }
410
411                                 break;
412                         }
413
414                         if ( c_mod->sm_values == NULL ) {
415                                 Debug( LDAP_DEBUG_TRACE,
416                                         "   backsql_modify_internal(): "
417                                         "no values given to delete "
418                                         "for attribute \"%s\" "
419                                         "-- deleting all values\n",
420                                         at->bam_ad->ad_cname.bv_val, 0, 0 );
421                                 goto del_all;
422                         }
423
424                         Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
425                                 "deleting values for attribute \"%s\"\n",
426                                 at->bam_ad->ad_cname.bv_val, 0, 0 );
427
428                         for ( i = 0, at_val = c_mod->sm_values;
429                                         at_val->bv_val != NULL;
430                                         i++, at_val++ ) {
431                                 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
432                                         pno = 1;
433                                         SQLBindParameter( sth, 1,
434                                                 SQL_PARAM_OUTPUT,
435                                                 SQL_C_ULONG, SQL_INTEGER,
436                                                 0, 0, &prc, 0, 0 );
437                                 } else {
438                                         pno = 0;
439                                 }
440                                 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
441 #ifdef BACKSQL_ARBITRARY_KEY
442                                 SQLBindParameter( sth, pno + 1 + po,
443                                         SQL_PARAM_INPUT, 
444                                         SQL_C_CHAR, SQL_VARCHAR,
445                                         0, 0, e_id->eid_keyval.bv_val, 0, 0 );
446 #else /* ! BACKSQL_ARBITRARY_KEY */
447                                 SQLBindParameter( sth, pno + 1 + po,
448                                         SQL_PARAM_INPUT, 
449                                         SQL_C_ULONG, SQL_INTEGER,
450                                         0, 0, &e_id->eid_keyval, 0, 0 );
451 #endif /* ! BACKSQL_ARBITRARY_KEY */
452
453                                 /*
454                                  * check for syntax needed here 
455                                  * maybe need binary bind?
456                                  */
457                                 SQLBindParameter( sth, pno + 2 - po,
458                                         SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
459                                         0, 0, at_val->bv_val, 
460                                         at_val->bv_len, 0 );
461
462                                 Debug( LDAP_DEBUG_TRACE,
463                                         "   backsql_modify_internal(): "
464                                         "executing \"%s\"\n", 
465                                         at->bam_delete_proc, 0, 0 );
466                                 rc = SQLExecDirect( sth, at->bam_delete_proc,
467                                                 SQL_NTS );
468                                 if ( rc != SQL_SUCCESS ) {
469                                         Debug( LDAP_DEBUG_TRACE,
470                                                 "   backsql_modify_internal(): "
471                                                 "delete_proc execution "
472                                                 "failed\n", 0, 0, 0 );
473                                         backsql_PrintErrors( bi->db_env,
474                                                         dbh, sth, rc );
475
476                                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
477                                                 rs->sr_err = LDAP_OTHER;
478                                                 rs->sr_text = "SQL-backend error";
479                                                 goto done;
480                                         }
481                                 }
482 #ifdef BACKSQL_REALLOC_STMT
483                                 SQLFreeStmt( sth, SQL_DROP );
484                                 SQLAllocStmt( dbh, &sth );
485 #endif /* BACKSQL_REALLOC_STMT */
486                         }
487                         break;
488                 }
489 #ifndef BACKSQL_REALLOC_STMT
490                 SQLFreeStmt( sth, SQL_RESET_PARAMS );
491 #else /* BACKSQL_REALLOC_STMT */
492                 SQLFreeStmt( sth, SQL_DROP );
493 #endif /* BACKSQL_REALLOC_STMT */
494         }
495
496 done:;
497         
498 #ifndef BACKSQL_REALLOC_STMT
499         SQLFreeStmt( sth, SQL_DROP );
500 #endif /* BACKSQL_REALLOC_STMT */
501
502         Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
503                 rs->sr_err, rs->sr_text ? ": " : "",
504                 rs->sr_text ? rs->sr_text : "" );
505
506         /*
507          * FIXME: should fail in case one change fails?
508          */
509         return rs->sr_err;
510 }
511
512 int
513 backsql_add( Operation *op, SlapReply *rs )
514 {
515         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
516         SQLHDBC                 dbh;
517         SQLHSTMT                sth;
518         unsigned long           new_keyval = 0;
519         long                    i;
520         RETCODE                 rc;
521         backsql_oc_map_rec      *oc = NULL;
522         backsql_at_map_rec      *at_rec = NULL;
523         backsql_entryID         parent_id = BACKSQL_ENTRYID_INIT;
524         Entry                   p;
525         Attribute               *at;
526         struct berval           *at_val;
527         struct berval           pdn;
528         /* first parameter #, parameter order */
529         SQLUSMALLINT            pno, po;
530         /* procedure return code */
531         int                     prc;
532         struct berval           realdn = BER_BVNULL,
533                                 realpdn = BER_BVNULL;
534
535         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
536                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
537
538         /* check schema */
539         if ( global_schemacheck ) {
540                 char            textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
541
542                 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
543                                 NULL,
544                                 &rs->sr_text, textbuf, sizeof( textbuf ) );
545                 if ( rs->sr_err != LDAP_SUCCESS ) {
546                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
547                                 "entry failed schema check -- aborting\n",
548                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
549                         goto done;
550                 }
551         }
552
553         /* search structural objectClass */
554         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
555                 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
556                         break;
557                 }
558         }
559
560         /* there must exist */
561         assert( at != NULL );
562
563         /* I guess we should play with sub/supertypes to find a suitable oc */
564         oc = backsql_name2oc( bi, &at->a_vals[0] );
565
566         if ( oc == NULL ) {
567                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
568                         "cannot map structuralObjectClass \"%s\" -- aborting\n",
569                         op->oq_add.rs_e->e_name.bv_val,
570                         at->a_vals[0].bv_val, 0 );
571                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
572                 rs->sr_text = "operation not permitted within namingContext";
573                 goto done;
574         }
575
576         if ( oc->bom_create_proc == NULL ) {
577                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
578                         "create procedure is not defined "
579                         "for structuralObjectClass \"%s\" - aborting\n",
580                         op->oq_add.rs_e->e_name.bv_val,
581                         at->a_vals[0].bv_val, 0 );
582                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
583                 rs->sr_text = "operation not permitted within namingContext";
584                 goto done;
585
586         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
587                         && oc->bom_create_keyval == NULL ) {
588                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
589                         "create procedure needs select procedure, "
590                         "but none is defined for structuralObjectClass \"%s\" "
591                         "- aborting\n",
592                         op->oq_add.rs_e->e_name.bv_val,
593                         at->a_vals[0].bv_val, 0 );
594                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
595                 rs->sr_text = "operation not permitted within namingContext";
596                 goto done;
597         }
598
599         rs->sr_err = backsql_get_db_conn( op, &dbh );
600         if ( rs->sr_err != LDAP_SUCCESS ) {
601                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
602                         "could not get connection handle - exiting\n", 
603                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
604                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
605                         ?  "SQL-backend error" : NULL;
606                 goto done;
607         }
608
609         /*
610          * Check if entry exists
611          */
612         realdn = op->oq_add.rs_e->e_name;
613         if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
614                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
615                         "backsql_api_dn2odbc(\"%s\") failed\n", 
616                         op->oq_add.rs_e->e_name.bv_val,
617                         op->oq_add.rs_e->e_name.bv_val, 0 );
618                 rs->sr_err = LDAP_OTHER;
619                 rs->sr_text = "SQL-backend error";
620                 goto done;
621         }
622
623         rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
624         if ( rs->sr_err == LDAP_SUCCESS ) {
625                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
626                         "entry exists\n",
627                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
628                 rs->sr_err = LDAP_ALREADY_EXISTS;
629                 goto done;
630         }
631
632         /*
633          * Get the parent dn and see if the corresponding entry exists.
634          */
635         if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
636                 pdn = slap_empty_bv;
637         } else {
638                 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
639         }
640
641         realpdn = pdn;
642         if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
643                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
644                         "backsql_api_dn2odbc(\"%s\") failed\n", 
645                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
646                 rs->sr_err = LDAP_OTHER;
647                 rs->sr_text = "SQL-backend error";
648                 goto done;
649         }
650
651         rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
652         if ( rs->sr_err != LDAP_SUCCESS ) {
653                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
654                         "could not lookup parent entry for new record \"%s\"\n",
655                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
656
657                 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
658                         goto done;
659                 }
660
661                 /*
662                  * no parent!
663                  *  if not attempting to add entry at suffix or with parent ""
664                  */
665                 if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
666                         || pdn.bv_len > 0 ) && !is_entry_glue( op->oq_add.rs_e ) )
667                 {
668                         Debug( LDAP_DEBUG_TRACE, "   backsql_add: %s denied\n",
669                                 pdn.bv_len == 0 ? "suffix" : "entry at root",
670                                 0, 0 );
671                         /*
672                          * Look for matched
673                          */
674                         while ( 1 ) {
675                                 struct berval   dn;
676                                 char            *matched = NULL;
677         
678                                 if ( realpdn.bv_val != pdn.bv_val ) {
679                                         ch_free( realpdn.bv_val );
680                                 }
681         
682                                 dn = pdn;
683                                 dnParent( &dn, &pdn );
684         
685                                 /*
686                                  * Empty DN ("") defaults to LDAP_SUCCESS
687                                  */
688                                 realpdn = pdn;
689                                 if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
690                                         Debug( LDAP_DEBUG_TRACE,
691                                                 "   backsql_add(\"%s\"): "
692                                                 "backsql_api_dn2odbc failed\n", 
693                                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
694                                         rs->sr_err = LDAP_OTHER;
695                                         rs->sr_text = "SQL-backend error";
696                                         goto done;
697                                 }
698         
699                                 rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
700                                 switch ( rs->sr_err ) {
701                                 case LDAP_NO_SUCH_OBJECT:
702                                         if ( pdn.bv_len > 0 ) {
703                                                 break;
704                                         }
705                                         /* fail over to next case */
706                                         
707                                 case LDAP_SUCCESS:
708                                         matched = pdn.bv_val;
709                                         /* fail over to next case */
710         
711                                 default:
712                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
713                                         rs->sr_matched = matched;
714                                         goto done;
715                                 } 
716                         }
717                 } else {
718
719 #ifdef BACKSQL_ARBITRARY_KEY
720                         ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
721 #else /* ! BACKSQL_ARBITRARY_KEY */
722                         parent_id.eid_id = 0;
723 #endif /* ! BACKSQL_ARBITRARY_KEY */
724                         rs->sr_err = LDAP_SUCCESS;
725                 }
726         }
727
728         /* check "children" pseudo-attribute access to parent */
729         p.e_attrs = NULL;
730         p.e_name = pdn;
731         dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
732         if ( !access_allowed( op, &p, slap_schema.si_ad_children,
733                                 NULL, ACL_WRITE, NULL ) ) {
734                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
735                 goto done;
736         }
737
738         /*
739          * create_proc is executed; if expect_return is set, then
740          * an output parameter is bound, which should contain 
741          * the id of the added row; otherwise the procedure
742          * is expected to return the id as the first column of a select
743          */
744
745         rc = SQLAllocStmt( dbh, &sth );
746         if ( rc != SQL_SUCCESS ) {
747                 rs->sr_err = LDAP_OTHER;
748                 rs->sr_text = "SQL-backend error";
749                 goto done;
750         }
751
752         if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
753                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
754                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
755         }
756
757         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): executing \"%s\"\n",
758                 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
759         rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
760         if ( rc != SQL_SUCCESS ) {
761                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
762                         "create_proc execution failed\n",
763                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
764                 backsql_PrintErrors( bi->db_env, dbh, sth, rc);
765                 SQLFreeStmt( sth, SQL_DROP );
766                 rs->sr_err = LDAP_OTHER;
767                 rs->sr_text = "SQL-backend error";
768                 goto done;
769         }
770         if ( op->o_noop ) {
771                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
772         }
773
774         if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
775                 SWORD           ncols;
776                 SQLINTEGER      value_len;
777
778                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
779 #ifndef BACKSQL_REALLOC_STMT
780                         SQLFreeStmt( sth, SQL_RESET_PARAMS );
781 #else /* BACKSQL_REALLOC_STMT */
782                         SQLFreeStmt( sth, SQL_DROP );
783                         rc = SQLAllocStmt( dbh, &sth );
784                         if ( rc != SQL_SUCCESS ) {
785                                 rs->sr_err = LDAP_OTHER;
786                                 rs->sr_text = "SQL-backend error";
787                                 goto done;
788                         }
789 #endif /* BACKSQL_REALLOC_STMT */
790
791                         rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
792                         if ( rc != SQL_SUCCESS ) {
793                                 rs->sr_err = LDAP_OTHER;
794                                 rs->sr_text = "SQL-backend error";
795                                 goto done;
796                         }
797                 }
798
799                 /*
800                  * the query to know the id of the inserted entry
801                  * must be embedded in the create procedure
802                  */
803                 rc = SQLNumResultCols( sth, &ncols );
804                 if ( rc != SQL_SUCCESS ) {
805                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
806                                 "create_proc result evaluation failed\n",
807                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
808                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
809                         SQLFreeStmt( sth, SQL_DROP );
810                         rs->sr_err = LDAP_OTHER;
811                         rs->sr_text = "SQL-backend error";
812                         goto done;
813
814                 } else if ( ncols != 1 ) {
815                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
816                                 "create_proc result is bogus (ncols=%d)\n",
817                                 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
818                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
819                         SQLFreeStmt( sth, SQL_DROP );
820                         rs->sr_err = LDAP_OTHER;
821                         rs->sr_text = "SQL-backend error";
822                         goto done;
823                 }
824
825 #if 0
826                 {
827                         SQLCHAR         colname[ 64 ];
828                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
829                         UDWORD          col_prec;
830
831                         /*
832                          * FIXME: check whether col_type is compatible,
833                          * if it can be null and so on ...
834                          */
835                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
836                                         &colname[ 0 ], 
837                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
838                                         &name_len, &col_type,
839                                         &col_prec, &col_scale, &col_null );
840                 }
841 #endif
842
843                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
844                                 (SQLPOINTER)&new_keyval, 
845                                 (SQLINTEGER)sizeof( new_keyval ), 
846                                 &value_len );
847
848                 rc = SQLFetch( sth );
849
850                 if ( value_len <= 0 ) {
851                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
852                                 "create_proc result is empty?\n",
853                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
854                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
855                         SQLFreeStmt( sth, SQL_DROP );
856                         rs->sr_err = LDAP_OTHER;
857                         rs->sr_text = "SQL-backend error";
858                         goto done;
859                 }
860         }
861
862 #ifndef BACKSQL_REALLOC_STMT
863         SQLFreeStmt( sth, SQL_RESET_PARAMS );
864 #else /* BACKSQL_REALLOC_STMT */
865         SQLFreeStmt( sth, SQL_DROP );
866 #endif /* BACKSQL_REALLOC_STMT */
867
868         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
869                 "create_proc returned keyval=%ld\n",
870                 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
871
872         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
873                 SQLUSMALLINT    currpos;
874
875                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
876                         "adding attribute \"%s\"\n", 
877                         at->a_desc->ad_cname.bv_val, 0, 0 );
878
879                 /*
880                  * Skip:
881                  * - the first occurrence of objectClass, which is used
882                  *   to determine how to bulid the SQL entry (FIXME ?!?)
883                  * - operational attributes
884                  *   empty attributes (FIXME ?!?)
885                  */
886                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
887                         continue;
888                 }
889
890                 at_rec = backsql_ad2at( oc, at->a_desc ); 
891   
892                 if ( at_rec == NULL ) {
893                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
894                                 "attribute \"%s\" is not registered "
895                                 "in objectclass \"%s\"\n",
896                                 op->oq_add.rs_e->e_name.bv_val,
897                                 at->a_desc->ad_cname.bv_val,
898                                 BACKSQL_OC_NAME( oc ) );
899
900                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
901                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
902                                 rs->sr_text = "operation not permitted "
903                                         "within namingContext";
904                                 goto done;
905                         }
906
907                         continue;
908                 }
909                 
910                 if ( at_rec->bam_add_proc == NULL ) {
911                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
912                                 "add procedure is not defined "
913                                 "for attribute \"%s\" "
914                                 "of structuralObjectClass \"%s\"\n",
915                                 op->oq_add.rs_e->e_name.bv_val,
916                                 at->a_desc->ad_cname.bv_val,
917                                 BACKSQL_OC_NAME( oc ) );
918
919                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
920                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
921                                 rs->sr_text = "operation not permitted "
922                                         "within namingContext";
923                                 goto done;
924                         }
925
926                         continue;
927                 }
928
929                 for ( i = 0, at_val = &at->a_vals[ i ];
930                                 at_val->bv_val != NULL;
931                                 i++, at_val = &at->a_vals[ i ] )
932                 {
933                         char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
934                         
935 #ifdef BACKSQL_REALLOC_STMT
936                         rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
937                         if ( rc != SQL_SUCCESS ) {
938
939                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
940                                         rs->sr_err = LDAP_OTHER;
941                                         rs->sr_text = "SQL-backend error";
942                                         goto done;
943                                 }
944
945                                 goto next_attr;
946                         }
947 #endif /* BACKSQL_REALLOC_STMT */
948
949                         if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
950                                 pno = 1;
951                                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
952                                                 SQL_C_ULONG, SQL_INTEGER,
953                                                 0, 0, &prc, 0, 0 );
954                         } else {
955                                 pno = 0;
956                         }
957
958                         po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
959                         currpos = pno + 1 + po;
960                         SQLBindParameter( sth, currpos,
961                                         SQL_PARAM_INPUT, SQL_C_ULONG,
962                                         SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
963                         currpos = pno + 2 - po;
964
965                         /*
966                          * Do not deal with the objectClass that is used
967                          * to build the entry
968                          */
969                         if ( at->a_desc == slap_schema.si_ad_objectClass ) {
970                                 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
971                                         continue;
972                                 }
973                         }
974
975                         /*
976                          * check for syntax needed here 
977                          * maybe need binary bind?
978                          */
979
980                         backsql_BindParamStr( sth, currpos,
981                                         at_val->bv_val, at_val->bv_len + 1 );
982
983 #ifdef LDAP_DEBUG
984                         snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
985                                         i, new_keyval );
986                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
987                                 "executing \"%s\" %s\n", 
988                                 op->oq_add.rs_e->e_name.bv_val,
989                                 at_rec->bam_add_proc, logbuf );
990 #endif
991 #ifndef BACKSQL_REALLOC_STMT
992                         rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
993 #else /* BACKSQL_REALLOC_STMT */
994                         rc = SQLExecute( sth );
995 #endif /* BACKSQL_REALLOC_STMT */
996                         if ( rc != SQL_SUCCESS ) {
997                                 Debug( LDAP_DEBUG_TRACE,
998                                         "   backsql_add(\"%s\"): "
999                                         "add_proc execution failed\n", 
1000                                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1001                                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1002
1003                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
1004                                         rs->sr_err = LDAP_OTHER;
1005                                         rs->sr_text = "SQL-backend error";
1006                                         goto done;
1007                                 }
1008                         }
1009 #ifndef BACKSQL_REALLOC_STMT
1010                         SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
1011 #else /* BACKSQL_REALLOC_STMT */
1012                         SQLFreeStmt( sth, SQL_DROP );
1013 #endif /* BACKSQL_REALLOC_STMT */
1014                 }
1015
1016 next_attr:;
1017         }
1018
1019 #ifdef BACKSQL_REALLOC_STMT
1020         rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
1021         if ( rc != SQL_SUCCESS ) {
1022                 rs->sr_err = LDAP_OTHER;
1023                 rs->sr_text = "SQL-backend error";
1024                 goto done;
1025         }
1026 #endif /* BACKSQL_REALLOC_STMT */
1027         
1028         backsql_BindParamStr( sth, 1, realdn.bv_val, BACKSQL_MAX_DN_LEN );
1029         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1030                         0, 0, &oc->bom_id, 0, 0 );
1031 #ifdef BACKSQL_ARBITRARY_KEY
1032         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
1033                         0, 0, parent_id.eid_id.bv_val, 0, 0 );
1034 #else /* ! BACKSQL_ARBITRARY_KEY */
1035         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1036                         0, 0, &parent_id.eid_id, 0, 0 );
1037 #endif /* ! BACKSQL_ARBITRARY_KEY */
1038         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
1039                         0, 0, &new_keyval, 0, 0 );
1040
1041         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\" for dn \"%s\"\n",
1042                         bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1043 #ifdef BACKSQL_ARBITRARY_KEY
1044         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1045                         "parent_id=%s, keyval=%ld\n",
1046                         oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1047 #else /* ! BACKSQL_ARBITRARY_KEY */
1048         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1049                         "parent_id=%ld, keyval=%ld\n",
1050                         oc->bom_id, parent_id.eid_id, new_keyval );
1051 #endif /* ! BACKSQL_ARBITRARY_KEY */
1052 #ifndef BACKSQL_REALLOC_STMT
1053         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1054 #else /* BACKSQL_REALLOC_STMT */
1055         rc = SQLExecute( sth );
1056 #endif /* BACKSQL_REALLOC_STMT */
1057         if ( rc != SQL_SUCCESS ) {
1058                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1059                         "could not insert ldap_entries record\n",
1060                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1061                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1062                 
1063                 /*
1064                  * execute delete_proc to delete data added !!!
1065                  */
1066                 SQLFreeStmt( sth, SQL_DROP );
1067                 rs->sr_err = LDAP_OTHER;
1068                 rs->sr_text = "SQL-backend error";
1069                 goto done;
1070         }
1071         
1072         SQLFreeStmt( sth, SQL_DROP );
1073
1074         /*
1075          * Commit only if all operations succeed
1076          */
1077         SQLTransact( SQL_NULL_HENV, dbh, 
1078                         op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1079
1080         /*
1081          * FIXME: NOOP does not work for add -- it works for all 
1082          * the other operations, and I don't get the reason :(
1083          * 
1084          * hint: there might be some autocommit in Postgres
1085          * so that when the unique id of the key table is
1086          * automatically increased, there's no rollback.
1087          * We might implement a "rollback" procedure consisting
1088          * in deleting that row.
1089          */
1090
1091 done:;
1092         send_ldap_result( op, rs );
1093
1094         if ( !BER_BVISNULL( &realdn )
1095                         && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
1096         {
1097                 ch_free( realdn.bv_val );
1098         }
1099         if ( !BER_BVISNULL( &realpdn ) && realpdn.bv_val != pdn.bv_val ) {
1100                 ch_free( realpdn.bv_val );
1101         }
1102         if ( !BER_BVISNULL( &parent_id.eid_dn ) ) {
1103                 backsql_free_entryID( &parent_id, 0 );
1104         }
1105
1106         Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1107                         op->oq_add.rs_e->e_name.bv_val,
1108                         rs->sr_err,
1109                         rs->sr_text ? rs->sr_text : "" );
1110
1111         return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1112 }
1113
1114 #endif /* SLAPD_SQL */
1115