]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/add.c
Sync with HEAD
[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         parent_id = BACKSQL_ENTRYID_INIT;
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         struct berval           realdn, realpdn;
520
521         Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
522                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
523
524         /* check schema */
525         if ( global_schemacheck ) {
526                 char            textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
527
528                 rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e,
529                                 NULL,
530                                 &rs->sr_text, textbuf, sizeof( textbuf ) );
531                 if ( rs->sr_err != LDAP_SUCCESS ) {
532                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
533                                 "entry failed schema check -- aborting\n",
534                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
535                         goto done;
536                 }
537         }
538
539         /* search structural objectClass */
540         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
541                 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
542                         break;
543                 }
544         }
545
546         /* there must exist */
547         assert( at != NULL );
548
549         /* I guess we should play with sub/supertypes to find a suitable oc */
550         oc = backsql_name2oc( bi, &at->a_vals[0] );
551
552         if ( oc == NULL ) {
553                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
554                         "cannot map structuralObjectClass \"%s\" -- aborting\n",
555                         op->oq_add.rs_e->e_name.bv_val,
556                         at->a_vals[0].bv_val, 0 );
557                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
558                 rs->sr_text = "operation not permitted within namingContext";
559                 goto done;
560         }
561
562         if ( oc->bom_create_proc == NULL ) {
563                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
564                         "create procedure is not defined "
565                         "for structuralObjectClass \"%s\" - aborting\n",
566                         op->oq_add.rs_e->e_name.bv_val,
567                         at->a_vals[0].bv_val, 0 );
568                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
569                 rs->sr_text = "operation not permitted within namingContext";
570                 goto done;
571
572         } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
573                         && oc->bom_create_keyval == NULL ) {
574                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
575                         "create procedure needs select procedure, "
576                         "but none is defined for structuralObjectClass \"%s\" "
577                         "- aborting\n",
578                         op->oq_add.rs_e->e_name.bv_val,
579                         at->a_vals[0].bv_val, 0 );
580                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
581                 rs->sr_text = "operation not permitted within namingContext";
582                 goto done;
583         }
584
585         rs->sr_err = backsql_get_db_conn( op, &dbh );
586         if ( rs->sr_err != LDAP_SUCCESS ) {
587                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
588                         "could not get connection handle - exiting\n", 
589                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
590                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
591                         ?  "SQL-backend error" : NULL;
592                 goto done;
593         }
594
595         /*
596          * Check if entry exists
597          */
598         realdn = op->oq_add.rs_e->e_name;
599         if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
600                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
601                         "backsql_api_dn2odbc(\"%s\") failed\n", 
602                         op->oq_add.rs_e->e_name.bv_val,
603                         op->oq_add.rs_e->e_name.bv_val, 0 );
604                 rs->sr_err = LDAP_OTHER;
605                 rs->sr_text = "SQL-backend error";
606                 goto done;
607         }
608
609         rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realdn );
610         if ( rs->sr_err == LDAP_SUCCESS ) {
611                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
612                         "entry exists\n",
613                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
614                 rs->sr_err = LDAP_ALREADY_EXISTS;
615                 goto done;
616         }
617
618         /*
619          * Check if parent exists
620          */
621         dnParent( &op->oq_add.rs_e->e_name, &pdn );
622         realpdn = pdn;
623         if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
624                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
625                         "backsql_api_dn2odbc(\"%s\") failed\n", 
626                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
627                 rs->sr_err = LDAP_OTHER;
628                 rs->sr_text = "SQL-backend error";
629                 goto done;
630         }
631
632         rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &realpdn );
633         if ( rs->sr_err != LDAP_SUCCESS ) {
634                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
635                         "could not lookup parent entry for new record \"%s\"\n",
636                         op->oq_add.rs_e->e_name.bv_val, pdn.bv_val, 0 );
637
638                 if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) {
639                         goto done;
640                 }
641
642                 /*
643                  * Look for matched
644                  */
645                 while ( 1 ) {
646                         struct berval   dn;
647                         char            *matched = NULL;
648
649                         if ( realpdn.bv_val != pdn.bv_val ) {
650                                 ch_free( realpdn.bv_val );
651                         }
652
653                         dn = pdn;
654                         dnParent( &dn, &pdn );
655
656                         /*
657                          * Empty DN ("") defaults to LDAP_SUCCESS
658                          */
659                         realpdn = pdn;
660                         if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
661                                 Debug( LDAP_DEBUG_TRACE,
662                                         "   backsql_add(\"%s\"): "
663                                         "backsql_api_dn2odbc failed\n", 
664                                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
665                                 rs->sr_err = LDAP_OTHER;
666                                 rs->sr_text = "SQL-backend error";
667                                 goto done;
668                         }
669
670                         rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
671                         switch ( rs->sr_err ) {
672                         case LDAP_NO_SUCH_OBJECT:
673                                 if ( pdn.bv_len > 0 ) {
674                                         break;
675                                 }
676                                 /* fail over to next case */
677                                 
678                         case LDAP_SUCCESS:
679                                 matched = pdn.bv_val;
680                                 /* fail over to next case */
681
682                         default:
683                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
684                                 rs->sr_matched = matched;
685                                 goto done;
686                         } 
687                 }
688         }
689
690         /*
691          * create_proc is executed; if expect_return is set, then
692          * an output parameter is bound, which should contain 
693          * the id of the added row; otherwise the procedure
694          * is expected to return the id as the first column of a select
695          */
696
697         p.e_attrs = NULL;
698         p.e_name = pdn;
699         dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
700         if ( !access_allowed( op, &p, slap_schema.si_ad_children,
701                                 NULL, ACL_WRITE, NULL ) ) {
702                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
703                 goto done;
704         }
705
706         rc = SQLAllocStmt( dbh, &sth );
707         if ( rc != SQL_SUCCESS ) {
708                 rs->sr_err = LDAP_OTHER;
709                 rs->sr_text = "SQL-backend error";
710                 goto done;
711         }
712
713         if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
714                 SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
715                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
716         }
717
718         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): executing \"%s\"\n",
719                 op->oq_add.rs_e->e_name.bv_val, oc->bom_create_proc, 0 );
720         rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS );
721         if ( rc != SQL_SUCCESS ) {
722                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
723                         "create_proc execution failed\n",
724                         op->oq_add.rs_e->e_name.bv_val, 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         if ( op->o_noop ) {
732                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
733         }
734
735         if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
736                 SWORD           ncols;
737                 SQLINTEGER      value_len;
738
739                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
740 #ifndef BACKSQL_REALLOC_STMT
741                         SQLFreeStmt( sth, SQL_RESET_PARAMS );
742 #else /* BACKSQL_REALLOC_STMT */
743                         SQLFreeStmt( sth, SQL_DROP );
744                         rc = SQLAllocStmt( dbh, &sth );
745                         if ( rc != SQL_SUCCESS ) {
746                                 rs->sr_err = LDAP_OTHER;
747                                 rs->sr_text = "SQL-backend error";
748                                 goto done;
749                         }
750 #endif /* BACKSQL_REALLOC_STMT */
751
752                         rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
753                         if ( rc != SQL_SUCCESS ) {
754                                 rs->sr_err = LDAP_OTHER;
755                                 rs->sr_text = "SQL-backend error";
756                                 goto done;
757                         }
758                 }
759
760                 /*
761                  * the query to know the id of the inserted entry
762                  * must be embedded in the create procedure
763                  */
764                 rc = SQLNumResultCols( sth, &ncols );
765                 if ( rc != SQL_SUCCESS ) {
766                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
767                                 "create_proc result evaluation failed\n",
768                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
769                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
770                         SQLFreeStmt( sth, SQL_DROP );
771                         rs->sr_err = LDAP_OTHER;
772                         rs->sr_text = "SQL-backend error";
773                         goto done;
774
775                 } else if ( ncols != 1 ) {
776                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
777                                 "create_proc result is bogus (ncols=%d)\n",
778                                 op->oq_add.rs_e->e_name.bv_val, ncols, 0 );
779                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
780                         SQLFreeStmt( sth, SQL_DROP );
781                         rs->sr_err = LDAP_OTHER;
782                         rs->sr_text = "SQL-backend error";
783                         goto done;
784                 }
785
786 #if 0
787                 {
788                         SQLCHAR         colname[ 64 ];
789                         SQLSMALLINT     name_len, col_type, col_scale, col_null;
790                         UDWORD          col_prec;
791
792                         /*
793                          * FIXME: check whether col_type is compatible,
794                          * if it can be null and so on ...
795                          */
796                         rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
797                                         &colname[ 0 ], 
798                                         (SQLUINTEGER)( sizeof( colname ) - 1 ),
799                                         &name_len, &col_type,
800                                         &col_prec, &col_scale, &col_null );
801                 }
802 #endif
803
804                 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
805                                 (SQLPOINTER)&new_keyval, 
806                                 (SQLINTEGER)sizeof( new_keyval ), 
807                                 &value_len );
808
809                 rc = SQLFetch( sth );
810
811                 if ( value_len <= 0 ) {
812                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
813                                 "create_proc result is empty?\n",
814                                 op->oq_add.rs_e->e_name.bv_val, 0, 0 );
815                         backsql_PrintErrors( bi->db_env, dbh, sth, rc);
816                         SQLFreeStmt( sth, SQL_DROP );
817                         rs->sr_err = LDAP_OTHER;
818                         rs->sr_text = "SQL-backend error";
819                         goto done;
820                 }
821         }
822
823 #ifndef BACKSQL_REALLOC_STMT
824         SQLFreeStmt( sth, SQL_RESET_PARAMS );
825 #else /* BACKSQL_REALLOC_STMT */
826         SQLFreeStmt( sth, SQL_DROP );
827 #endif /* BACKSQL_REALLOC_STMT */
828
829         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
830                 "create_proc returned keyval=%ld\n",
831                 op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
832
833         for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
834                 SQLUSMALLINT    currpos;
835
836                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
837                         "adding attribute \"%s\"\n", 
838                         at->a_desc->ad_cname.bv_val, 0, 0 );
839
840                 /*
841                  * Skip:
842                  * - the first occurrence of objectClass, which is used
843                  *   to determine how to bulid the SQL entry (FIXME ?!?)
844                  * - operational attributes
845                  *   empty attributes (FIXME ?!?)
846                  */
847                 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
848                         continue;
849                 }
850
851                 at_rec = backsql_ad2at( oc, at->a_desc ); 
852   
853                 if ( at_rec == NULL ) {
854                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
855                                 "attribute \"%s\" is not registered "
856                                 "in objectclass \"%s\"\n",
857                                 op->oq_add.rs_e->e_name.bv_val,
858                                 at->a_desc->ad_cname.bv_val,
859                                 BACKSQL_OC_NAME( oc ) );
860
861                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
862                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
863                                 rs->sr_text = "operation not permitted "
864                                         "within namingContext";
865                                 goto done;
866                         }
867
868                         continue;
869                 }
870                 
871                 if ( at_rec->bam_add_proc == NULL ) {
872                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
873                                 "add procedure is not defined "
874                                 "for attribute \"%s\" "
875                                 "of structuralObjectClass \"%s\"\n",
876                                 op->oq_add.rs_e->e_name.bv_val,
877                                 at->a_desc->ad_cname.bv_val,
878                                 BACKSQL_OC_NAME( oc ) );
879
880                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
881                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
882                                 rs->sr_text = "operation not permitted "
883                                         "within namingContext";
884                                 goto done;
885                         }
886
887                         continue;
888                 }
889
890 #ifdef BACKSQL_REALLOC_STMT
891                 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
892                 if ( rc != SQL_SUCCESS ) {
893
894                         if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
895                                 rs->sr_err = LDAP_OTHER;
896                                 rs->sr_text = "SQL-backend error";
897                                 goto done;
898                         }
899
900                         continue;
901                 }
902 #endif /* BACKSQL_REALLOC_STMT */
903
904                 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
905                         pno = 1;
906                         SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
907                                         SQL_C_ULONG, SQL_INTEGER,
908                                         0, 0, &prc, 0, 0 );
909                 } else {
910                         pno = 0;
911                 }
912
913                 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
914                 currpos = pno + 1 + po;
915                 SQLBindParameter( sth, currpos,
916                                 SQL_PARAM_INPUT, SQL_C_ULONG,
917                                 SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
918                 currpos = pno + 2 - po;
919
920                 for ( i = 0, at_val = &at->a_vals[ i ];
921                                 at_val->bv_val != NULL;
922                                 i++, at_val = &at->a_vals[ i ] ) {
923                         char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
924
925                         /*
926                          * Do not deal with the objectClass that is used
927                          * to build the entry
928                          */
929                         if ( at->a_desc == slap_schema.si_ad_objectClass ) {
930                                 if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
931                                         continue;
932                                 }
933                         }
934
935                         /*
936                          * check for syntax needed here 
937                          * maybe need binary bind?
938                          */
939
940                         backsql_BindParamStr( sth, currpos,
941                                         at_val->bv_val, at_val->bv_len + 1 );
942
943 #ifdef LDAP_DEBUG
944                         snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
945                                         i, new_keyval );
946                         Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
947                                 "executing \"%s\" %s\n", 
948                                 op->oq_add.rs_e->e_name.bv_val,
949                                 at_rec->bam_add_proc, logbuf );
950 #endif
951 #ifndef BACKSQL_REALLOC_STMT
952                         rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
953 #else /* BACKSQL_REALLOC_STMT */
954                         rc = SQLExecute( sth );
955 #endif /* BACKSQL_REALLOC_STMT */
956                         if ( rc != SQL_SUCCESS ) {
957                                 Debug( LDAP_DEBUG_TRACE,
958                                         "   backsql_add(\"%s\"): "
959                                         "add_proc execution failed\n", 
960                                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
961                                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
962
963                                 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
964                                         rs->sr_err = LDAP_OTHER;
965                                         rs->sr_text = "SQL-backend error";
966                                         goto done;
967                                 }
968                         }
969                 }
970 #ifndef BACKSQL_REALLOC_STMT
971                 SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
972 #else /* BACKSQL_REALLOC_STMT */
973                 SQLFreeStmt( sth, SQL_DROP );
974 #endif /* BACKSQL_REALLOC_STMT */
975         }
976
977 #ifdef BACKSQL_REALLOC_STMT
978         rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
979         if ( rc != SQL_SUCCESS ) {
980                 rs->sr_err = LDAP_OTHER;
981                 rs->sr_text = "SQL-backend error";
982                 goto done;
983         }
984 #endif /* BACKSQL_REALLOC_STMT */
985         
986         backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
987                         BACKSQL_MAX_DN_LEN );
988         SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
989                         0, 0, &oc->bom_id, 0, 0 );
990 #ifdef BACKSQL_ARBITRARY_KEY
991         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
992                         0, 0, parent_id.eid_id.bv_val, 0, 0 );
993 #else /* ! BACKSQL_ARBITRARY_KEY */
994         SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
995                         0, 0, &parent_id.eid_id, 0, 0 );
996 #endif /* ! BACKSQL_ARBITRARY_KEY */
997         SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
998                         0, 0, &new_keyval, 0, 0 );
999
1000         Debug( LDAP_DEBUG_TRACE, "   backsql_add(): executing \"%s\" for dn \"%s\"\n",
1001                         bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 );
1002 #ifdef BACKSQL_ARBITRARY_KEY
1003         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1004                         "parent_id=%s, keyval=%ld\n",
1005                         oc->bom_id, parent_id.eid_id.bv_val, new_keyval );
1006 #else /* ! BACKSQL_ARBITRARY_KEY */
1007         Debug( LDAP_DEBUG_TRACE, "                  for oc_map_id=%ld, "
1008                         "parent_id=%ld, keyval=%ld\n",
1009                         oc->bom_id, parent_id.eid_id, new_keyval );
1010 #endif /* ! BACKSQL_ARBITRARY_KEY */
1011 #ifndef BACKSQL_REALLOC_STMT
1012         rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
1013 #else /* BACKSQL_REALLOC_STMT */
1014         rc = SQLExecute( sth );
1015 #endif /* BACKSQL_REALLOC_STMT */
1016         if ( rc != SQL_SUCCESS ) {
1017                 Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1018                         "could not insert ldap_entries record\n",
1019                         op->oq_add.rs_e->e_name.bv_val, 0, 0 );
1020                 backsql_PrintErrors( bi->db_env, dbh, sth, rc );
1021                 
1022                 /*
1023                  * execute delete_proc to delete data added !!!
1024                  */
1025                 SQLFreeStmt( sth, SQL_DROP );
1026                 rs->sr_err = LDAP_OTHER;
1027                 rs->sr_text = "SQL-backend error";
1028                 goto done;
1029         }
1030         
1031         SQLFreeStmt( sth, SQL_DROP );
1032
1033         /*
1034          * Commit only if all operations succeed
1035          */
1036         SQLTransact( SQL_NULL_HENV, dbh, 
1037                         op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
1038
1039         /*
1040          * FIXME: NOOP does not work for add -- it works for all 
1041          * the other operations, and I don't get the reason :(
1042          * 
1043          * hint: there might be some autocommit in Postgres
1044          * so that when the unique id of the key table is
1045          * automatically increased, there's no rollback.
1046          * We might implement a "rollback" procedure consisting
1047          * in deleting that row.
1048          */
1049
1050 done:;
1051         send_ldap_result( op, rs );
1052
1053         if ( realdn.bv_val != op->oq_add.rs_e->e_name.bv_val ) {
1054                 ch_free( realdn.bv_val );
1055         }
1056         if ( realpdn.bv_val != pdn.bv_val ) {
1057                 ch_free( realpdn.bv_val );
1058         }
1059         if ( parent_id.eid_dn.bv_val != NULL ) {
1060                 backsql_free_entryID( &parent_id, 0 );
1061         }
1062
1063         Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
1064                         op->oq_add.rs_e->e_name.bv_val,
1065                         rs->sr_err,
1066                         rs->sr_text ? rs->sr_text : "" );
1067
1068         return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 );
1069 }
1070
1071 #endif /* SLAPD_SQL */
1072