]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/entry-id.c
ITS#3796 fix IDL cache lock setup/teardown
[openldap] / servers / slapd / back-sql / entry-id.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * Portions Copyright 2004 Mark Adamson.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Dmitry Kovalev for inclusion
20  * by OpenLDAP Software.  Additional significant contributors include
21  * Pierangelo Masarati and Mark Adamson.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include "ac/string.h"
29
30 #include "slap.h"
31 #include "proto-sql.h"
32
33 #ifdef BACKSQL_ARBITRARY_KEY
34 struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR );
35 #endif /* BACKSQL_ARBITRARY_KEY */
36
37 backsql_entryID *
38 backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit )
39 {
40         backsql_entryID         *next;
41
42         assert( id );
43
44         next = id->eid_next;
45
46         if ( !BER_BVISNULL( &id->eid_ndn ) ) {
47                 if ( !BER_BVISNULL( &id->eid_dn )
48                                 && id->eid_dn.bv_val != id->eid_ndn.bv_val )
49                 {
50                         op->o_tmpfree( id->eid_dn.bv_val, op->o_tmpmemctx );
51                         BER_BVZERO( &id->eid_dn );
52                 }
53
54                 op->o_tmpfree( id->eid_ndn.bv_val, op->o_tmpmemctx );
55                 BER_BVZERO( &id->eid_ndn );
56         }
57
58 #ifdef BACKSQL_ARBITRARY_KEY
59         if ( !BER_BVISNULL( &id->eid_id ) ) {
60                 op->o_tmpfree( id->eid_id.bv_val, op->o_tmpmemctx );
61                 BER_BVZERO( &id->eid_id );
62         }
63
64         if ( !BER_BVISNULL( &id->eid_keyval ) ) {
65                 op->o_tmpfree( id->eid_keyval.bv_val, op->o_tmpmemctx );
66                 BER_BVZERO( &id->eid_keyval );
67         }
68 #endif /* BACKSQL_ARBITRARY_KEY */
69
70         if ( freeit ) {
71                 op->o_tmpfree( id, op->o_tmpmemctx );
72         }
73
74         return next;
75 }
76
77 /*
78  * NOTE: the dn must be normalized
79  */
80 int
81 backsql_dn2id(
82         Operation               *op,
83         SlapReply               *rs,
84         SQLHDBC                 dbh,
85         struct berval           *ndn,
86         backsql_entryID         *id,
87         int                     matched,
88         int                     muck )
89 {
90         backsql_info            *bi = op->o_bd->be_private;
91         SQLHSTMT                sth = SQL_NULL_HSTMT; 
92         BACKSQL_ROW_NTS         row;
93         RETCODE                 rc;
94         int                     res;
95         struct berval           realndn = BER_BVNULL;
96
97         /* TimesTen */
98         char                    upperdn[ BACKSQL_MAX_DN_LEN + 1 ];
99         struct berval           tbbDN;
100         int                     i, j;
101
102         /*
103          * NOTE: id can be NULL; in this case, the function
104          * simply checks whether the DN can be successfully 
105          * turned into an ID, returning LDAP_SUCCESS for
106          * positive cases, or the most appropriate error
107          */
108
109         Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", 
110                         ndn->bv_val, id == NULL ? " (no ID expected)" : "",
111                         matched ? " matched expected" : "" );
112
113         if ( id ) {
114                 /* NOTE: trap inconsistencies */
115                 assert( BER_BVISNULL( &id->eid_ndn ) );
116         }
117
118         if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
119                 Debug( LDAP_DEBUG_TRACE, 
120                         "   backsql_dn2id(\"%s\"): DN length=%ld "
121                         "exceeds max DN length %d:\n",
122                         ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN );
123                 return LDAP_OTHER;
124         }
125
126         /* return baseObject if available and matches */
127         /* FIXME: if ndn is already mucked, we cannot check this */
128         if ( bi->sql_baseObject != NULL &&
129                         dn_match( ndn, &bi->sql_baseObject->e_nname ) )
130         {
131                 if ( id != NULL ) {
132 #ifdef BACKSQL_ARBITRARY_KEY
133                         ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv,
134                                         op->o_tmpmemctx );
135                         ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv,
136                                         op->o_tmpmemctx );
137 #else /* ! BACKSQL_ARBITRARY_KEY */
138                         id->eid_id = BACKSQL_BASEOBJECT_ID;
139                         id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL;
140 #endif /* ! BACKSQL_ARBITRARY_KEY */
141                         id->eid_oc_id = BACKSQL_BASEOBJECT_OC;
142
143                         ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname,
144                                         op->o_tmpmemctx );
145                         ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name,
146                                         op->o_tmpmemctx );
147
148                         id->eid_next = NULL;
149                 }
150
151                 return LDAP_SUCCESS;
152         }
153         
154         /* begin TimesTen */
155         Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): id_query \"%s\"\n",
156                         ndn->bv_val, bi->sql_id_query, 0 );
157         assert( bi->sql_id_query );
158         rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 );
159         if ( rc != SQL_SUCCESS ) {
160                 Debug( LDAP_DEBUG_TRACE, 
161                         "   backsql_dn2id(\"%s\"): "
162                         "error preparing SQL:\n   %s", 
163                         ndn->bv_val, bi->sql_id_query, 0 );
164                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
165                 res = LDAP_OTHER;
166                 goto done;
167         }
168
169         realndn = *ndn;
170         if ( muck ) {
171                 if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
172                         Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
173                                 "backsql_api_dn2odbc(\"%s\") failed\n", 
174                                 ndn->bv_val, realndn.bv_val, 0 );
175                         res = LDAP_OTHER;
176                         goto done;
177                 }
178         }
179
180         if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
181                 /*
182                  * Prepare an upper cased, byte reversed version 
183                  * that can be searched using indexes
184                  */
185
186                 for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--)
187                 {
188                         upperdn[ i ] = realndn.bv_val[ j ];
189                 }
190                 upperdn[ i ] = '\0';
191                 ldap_pvt_str2upper( upperdn );
192
193                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
194                                 "upperdn=\"%s\"\n",
195                                 ndn->bv_val, upperdn, 0 );
196                 ber_str2bv( upperdn, 0, 0, &tbbDN );
197
198         } else {
199                 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
200                         AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 );
201                         ldap_pvt_str2upper( upperdn );
202                         Debug( LDAP_DEBUG_TRACE,
203                                 "   backsql_dn2id(\"%s\"): "
204                                 "upperdn=\"%s\"\n",
205                                 ndn->bv_val, upperdn, 0 );
206                         ber_str2bv( upperdn, 0, 0, &tbbDN );
207
208                 } else {
209                         tbbDN = realndn;
210                 }
211         }
212
213         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN );
214         if ( rc != SQL_SUCCESS) {
215                 /* end TimesTen */ 
216                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
217                         "error binding dn=\"%s\" parameter:\n", 
218                         ndn->bv_val, tbbDN.bv_val, 0 );
219                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
220                 res = LDAP_OTHER;
221                 goto done;
222         }
223
224         rc = SQLExecute( sth );
225         if ( rc != SQL_SUCCESS ) {
226                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
227                         "error executing query (\"%s\", \"%s\"):\n", 
228                         ndn->bv_val, bi->sql_id_query, tbbDN.bv_val );
229                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
230                 res = LDAP_OTHER;
231                 goto done;
232         }
233
234         backsql_BindRowAsStrings( sth, &row );
235         rc = SQLFetch( sth );
236         if ( BACKSQL_SUCCESS( rc ) ) {
237                 char    buf[ SLAP_TEXT_BUFLEN ];
238
239 #ifdef LDAP_DEBUG
240                 snprintf( buf, sizeof(buf),
241                         "id=%s keyval=%s oc_id=%s dn=%s",
242                         row.cols[ 0 ], row.cols[ 1 ],
243                         row.cols[ 2 ], row.cols[ 3 ] );
244                 Debug( LDAP_DEBUG_TRACE,
245                         "   backsql_dn2id(\"%s\"): %s\n",
246                         ndn->bv_val, buf, 0 );
247 #endif /* LDAP_DEBUG */
248
249                 res = LDAP_SUCCESS;
250                 if ( id != NULL ) {
251                         struct berval   dn;
252
253 #ifdef BACKSQL_ARBITRARY_KEY
254                         ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id,
255                                         op->o_tmpmemctx );
256                         ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval,
257                                         op->o_tmpmemctx );
258 #else /* ! BACKSQL_ARBITRARY_KEY */
259                         id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
260                         id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
261 #endif /* ! BACKSQL_ARBITRARY_KEY */
262                         id->eid_oc_id = strtol( row.cols[ 2 ], NULL, 0 );
263
264                         ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
265
266                         if ( backsql_api_odbc2dn( op, rs, &dn ) ) {
267                                 res = LDAP_OTHER;
268
269                         } else {
270                                 res = dnPrettyNormal( NULL, &dn,
271                                                 &id->eid_dn, &id->eid_ndn,
272                                                 op->o_tmpmemctx );
273                                 if ( res != LDAP_SUCCESS ) {
274                                         Debug( LDAP_DEBUG_TRACE,
275                                                 "   backsql_dn2id(\"%s\"): "
276                                                 "dnPrettyNormal failed (%d: %s)\n",
277                                                 realndn.bv_val, res,
278                                                 ldap_err2string( res ) );
279
280                                         /* cleanup... */
281                                         (void)backsql_free_entryID( op, id, 0 );
282                                 }
283
284                                 if ( dn.bv_val != row.cols[ 3 ] ) {
285                                         free( dn.bv_val );
286                                 }
287                         }
288
289                         id->eid_next = NULL;
290                 }
291
292         } else {
293                 res = LDAP_NO_SUCH_OBJECT;
294                 if ( matched ) {
295                         struct berval   pdn = *ndn;
296
297                         /*
298                          * Look for matched
299                          */
300                         rs->sr_matched = NULL;
301                         while ( !be_issuffix( op->o_bd, &pdn ) ) {
302                                 char            *matchedDN = NULL;
303         
304                                 dnParent( &pdn, &pdn );
305         
306                                 /*
307                                  * Empty DN ("") defaults to LDAP_SUCCESS
308                                  */
309                                 rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 );
310                                 switch ( rs->sr_err ) {
311                                 case LDAP_NO_SUCH_OBJECT:
312                                         /* try another one */
313                                         break;
314                                         
315                                 case LDAP_SUCCESS:
316                                         matchedDN = pdn.bv_val;
317                                         /* fail over to next case */
318         
319                                 default:
320                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
321                                         rs->sr_matched = matchedDN;
322                                         goto done;
323                                 } 
324                         }
325                 }
326         }
327         backsql_FreeRow( &row );
328
329 done:;
330         Debug( LDAP_DEBUG_TRACE,
331                 "<==backsql_dn2id(\"%s\"): err=%d\n",
332                 ndn->bv_val, res, 0 );
333         if ( sth != SQL_NULL_HSTMT ) {
334                 SQLFreeStmt( sth, SQL_DROP );
335         }
336
337         if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) {
338                 ch_free( realndn.bv_val );
339         }
340
341         return res;
342 }
343
344 int
345 backsql_count_children(
346         backsql_info            *bi,
347         SQLHDBC                 dbh,
348         struct berval           *dn,
349         unsigned long           *nchildren )
350 {
351         SQLHSTMT                sth = SQL_NULL_HSTMT;
352         BACKSQL_ROW_NTS         row;
353         RETCODE                 rc;
354         int                     res = LDAP_SUCCESS;
355
356         Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn=\"%s\"\n", 
357                         dn->bv_val, 0, 0 );
358
359         if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) {
360                 Debug( LDAP_DEBUG_TRACE, 
361                         "backsql_count_children(): DN \"%s\" (%ld bytes) "
362                         "exceeds max DN length (%d):\n",
363                         dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN );
364                 return LDAP_OTHER;
365         }
366         
367         /* begin TimesTen */
368         Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n", 
369                         bi->sql_has_children_query, 0, 0);
370         assert( bi->sql_has_children_query );
371         rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 );
372         if ( rc != SQL_SUCCESS ) {
373                 Debug( LDAP_DEBUG_TRACE, 
374                         "backsql_count_children(): error preparing SQL:\n%s", 
375                         bi->sql_has_children_query, 0, 0);
376                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
377                 SQLFreeStmt( sth, SQL_DROP );
378                 return LDAP_OTHER;
379         }
380
381         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, dn );
382         if ( rc != SQL_SUCCESS) {
383                 /* end TimesTen */ 
384                 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
385                         "error binding dn=\"%s\" parameter:\n", 
386                         dn->bv_val, 0, 0 );
387                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
388                 SQLFreeStmt( sth, SQL_DROP );
389                 return LDAP_OTHER;
390         }
391
392         rc = SQLExecute( sth );
393         if ( rc != SQL_SUCCESS ) {
394                 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
395                         "error executing query (\"%s\", \"%s\"):\n", 
396                         bi->sql_has_children_query, dn->bv_val, 0 );
397                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
398                 SQLFreeStmt( sth, SQL_DROP );
399                 return LDAP_OTHER;
400         }
401
402         backsql_BindRowAsStrings( sth, &row );
403         
404         rc = SQLFetch( sth );
405         if ( BACKSQL_SUCCESS( rc ) ) {
406                 char *end;
407
408                 *nchildren = strtol( row.cols[ 0 ], &end, 0 );
409                 if ( end[ 0 ] != '\0' && end[0] != '.' ) {
410                         /* FIXME: braindead RDBMSes return
411                          * a fractional number from COUNT!
412                          */
413                         res = LDAP_OTHER;
414                 }
415
416         } else {
417                 res = LDAP_OTHER;
418         }
419         backsql_FreeRow( &row );
420
421         SQLFreeStmt( sth, SQL_DROP );
422
423         Debug( LDAP_DEBUG_TRACE, "<==backsql_count_children(): %lu\n",
424                         *nchildren, 0, 0 );
425
426         return res;
427 }
428
429 int
430 backsql_has_children(
431         backsql_info            *bi,
432         SQLHDBC                 dbh,
433         struct berval           *dn )
434 {
435         unsigned long   nchildren;
436         int             rc;
437
438         rc = backsql_count_children( bi, dbh, dn, &nchildren );
439
440         if ( rc == LDAP_SUCCESS ) {
441                 return nchildren > 0 ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
442         }
443
444         return rc;
445 }
446
447 static int
448 backsql_get_attr_vals( void *v_at, void *v_bsi )
449 {
450         backsql_at_map_rec      *at = v_at;
451         backsql_srch_info       *bsi = v_bsi;
452         backsql_info            *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
453         RETCODE                 rc;
454         SQLHSTMT                sth = SQL_NULL_HSTMT;
455         BACKSQL_ROW_NTS         row;
456         unsigned long           i,
457                                 k = 0,
458                                 oldcount = 0;
459 #ifdef BACKSQL_COUNTQUERY
460         unsigned long           count,
461                                 countsize = sizeof( count ),
462                                 j;
463         Attribute               *attr = NULL;
464
465         slap_mr_normalize_func          *normfunc = NULL;
466 #endif /* BACKSQL_COUNTQUERY */
467 #ifdef BACKSQL_PRETTY_VALIDATE
468         slap_syntax_validate_func       *validate = NULL;
469         slap_syntax_transform_func      *pretty = NULL;
470 #endif /* BACKSQL_PRETTY_VALIDATE */
471
472         assert( at );
473         assert( bsi );
474
475 #ifdef BACKSQL_ARBITRARY_KEY
476         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
477                 "oc=\"%s\" attr=\"%s\" keyval=%s\n",
478                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
479                 bsi->bsi_c_eid->eid_keyval.bv_val );
480 #else /* ! BACKSQL_ARBITRARY_KEY */
481         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
482                 "oc=\"%s\" attr=\"%s\" keyval=%ld\n",
483                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
484                 bsi->bsi_c_eid->eid_keyval );
485 #endif /* ! BACKSQL_ARBITRARY_KEY */
486
487 #ifdef BACKSQL_PRETTY_VALIDATE
488         validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate;
489         pretty =  at->bam_ad->ad_type->sat_syntax->ssyn_pretty;
490
491         if ( validate == NULL && pretty == NULL ) {
492                 return 1;
493         }
494 #endif /* BACKSQL_PRETTY_VALIDATE */
495
496 #ifdef BACKSQL_COUNTQUERY
497         if ( at->bam_ad->ad_type->sat_equality ) {
498                 normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize;
499         }
500
501         /* Count how many rows will be returned. This avoids memory 
502          * fragmentation that can result from loading the values in 
503          * one by one and using realloc() 
504          */
505         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 );
506         if ( rc != SQL_SUCCESS ) {
507                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
508                         "error preparing count query: %s\n",
509                         at->bam_countquery, 0, 0 );
510                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
511                 return 1;
512         }
513
514         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
515                         &bsi->bsi_c_eid->eid_keyval );
516         if ( rc != SQL_SUCCESS ) {
517                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
518                         "error binding key value parameter\n", 0, 0, 0 );
519                 SQLFreeStmt( sth, SQL_DROP );
520                 return 1;
521         }
522
523         rc = SQLExecute( sth );
524         if ( ! BACKSQL_SUCCESS( rc ) ) {
525                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
526                         "error executing attribute count query '%s'\n",
527                         at->bam_countquery, 0, 0 );
528                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
529                 SQLFreeStmt( sth, SQL_DROP );
530                 return 1;
531         }
532
533         SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG,
534                         (SQLPOINTER)&count,
535                         (SQLINTEGER)sizeof( count ),
536                         &countsize );
537
538         rc = SQLFetch( sth );
539         if ( rc != SQL_SUCCESS ) {
540                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
541                         "error fetch results of count query: %s\n",
542                         at->bam_countquery, 0, 0 );
543                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
544                 SQLFreeStmt( sth, SQL_DROP );
545                 return 1;
546         }
547
548         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
549                 "number of values in query: %d\n", count, 0, 0 );
550         SQLFreeStmt( sth, SQL_DROP );
551         if ( count == 0 ) {
552                 return 1;
553         }
554
555         attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad );
556         if ( attr != NULL ) {
557                 BerVarray       tmp;
558
559                 if ( attr->a_vals != NULL ) {
560                         for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ )
561                                 /* just count */ ;
562                 }
563
564                 tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
565                 if ( tmp == NULL ) {
566                         return 1;
567                 }
568                 attr->a_vals = tmp;
569                 memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
570
571                 if ( normfunc ) {
572                         tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
573                         if ( tmp == NULL ) {
574                                 return 1;
575                         }
576                         attr->a_nvals = tmp;
577                         memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
578
579                 } else {
580                         attr->a_nvals = attr->a_vals;
581                 }
582
583         } else {
584                 Attribute       **ap;
585
586                 /* Make space for the array of values */
587                 attr = (Attribute *) ch_malloc( sizeof( Attribute ) );
588                 attr->a_desc = at->bam_ad;
589                 attr->a_flags = 0;
590                 attr->a_next = NULL;
591                 attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
592                 if ( attr->a_vals == NULL ) {
593                         Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
594                         ch_free( attr );
595                         return 1;
596                 }
597                 memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) );
598                 if ( normfunc ) {
599                         attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
600                         if ( attr->a_nvals == NULL ) {
601                                 ch_free( attr->a_vals );
602                                 ch_free( attr );
603                                 return 1;
604
605                         } else {
606                                 memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) );
607                         }
608
609                 } else {
610                         attr->a_nvals = attr->a_vals;
611                 }
612
613                 for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
614                         /* goto last */ ;
615                 *ap =  attr;
616         }
617 #endif /* BACKSQL_COUNTQUERY */
618
619         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
620         if ( rc != SQL_SUCCESS ) {
621                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
622                         "error preparing query: %s\n", at->bam_query, 0, 0 );
623                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
624                 return 1;
625         }
626
627         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
628                         &bsi->bsi_c_eid->eid_keyval );
629         if ( rc != SQL_SUCCESS ) {
630                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
631                         "error binding key value parameter\n", 0, 0, 0 );
632                 return 1;
633         }
634
635 #ifdef BACKSQL_TRACE
636 #ifdef BACKSQL_ARBITRARY_KEY
637         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
638                 "query=\"%s\" keyval=%s\n", at->bam_query,
639                 bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
640 #else /* !BACKSQL_ARBITRARY_KEY */
641         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
642                 "query=\"%s\" keyval=%d\n", at->bam_query,
643                 bsi->bsi_c_eid->eid_keyval, 0 );
644 #endif /* ! BACKSQL_ARBITRARY_KEY */
645 #endif /* BACKSQL_TRACE */
646
647         rc = SQLExecute( sth );
648         if ( ! BACKSQL_SUCCESS( rc ) ) {
649                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
650                         "error executing attribute query \"%s\"\n",
651                         at->bam_query, 0, 0 );
652                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
653                 SQLFreeStmt( sth, SQL_DROP );
654                 return 1;
655         }
656
657         backsql_BindRowAsStrings( sth, &row );
658 #ifdef BACKSQL_COUNTQUERY
659         j = oldcount;
660 #endif /* BACKSQL_COUNTQUERY */
661         for ( rc = SQLFetch( sth ), k = 0;
662                         BACKSQL_SUCCESS( rc );
663                         rc = SQLFetch( sth ), k++ )
664         {
665                 for ( i = 0; i < row.ncols; i++ ) {
666
667                         if ( row.value_len[ i ] > 0 ) {
668                                 struct berval           bv;
669                                 int                     retval;
670 #ifdef BACKSQL_TRACE
671                                 AttributeDescription    *ad = NULL;
672                                 const char              *text;
673
674                                 retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
675                                 if ( retval != LDAP_SUCCESS ) {
676                                         Debug( LDAP_DEBUG_ANY,
677                                                 "==>backsql_get_attr_vals(\"%s\"): "
678                                                 "unable to find AttributeDescription %s "
679                                                 "in schema (%d)\n",
680                                                 bsi->bsi_e->e_name.bv_val,
681                                                 row.col_names[ i ].bv_val, retval );
682                                         return 1;
683                                 }
684
685                                 if ( ad != at->bam_ad ) {
686                                         Debug( LDAP_DEBUG_ANY,
687                                                 "==>backsql_get_attr_vals(\"%s\"): "
688                                                 "column name %s differs from "
689                                                 "AttributeDescription %s\n",
690                                                 bsi->bsi_e->e_name.bv_val,
691                                                 ad->ad_cname.bv_val,
692                                                 at->bam_ad->ad_cname.bv_val );
693                                         return 1;
694                                 }
695 #endif /* BACKSQL_TRACE */
696
697                                 /*
698                                  * FIXME: what if a binary 
699                                  * is fetched?
700                                  */
701                                 ber_str2bv( row.cols[ i ], 0, 0, &bv );
702
703 #ifdef BACKSQL_PRETTY_VALIDATE
704                                 if ( pretty ) {
705                                         struct berval   pbv;
706
707                                         retval = pretty( at->bam_ad->ad_type->sat_syntax,
708                                                 &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
709                                         bv = pbv;
710
711                                 } else {
712                                         retval = validate( at->bam_ad->ad_type->sat_syntax,
713                                                 &bv );
714                                 }
715
716                                 if ( retval != LDAP_SUCCESS ) {
717                                         char    buf[ SLAP_TEXT_BUFLEN ];
718
719                                         /* FIXME: we're ignoring invalid values,
720                                          * but we're accepting the attributes;
721                                          * should we fail at all? */
722                                         snprintf( buf, sizeof( buf ),
723                                                         "unable to %s value #%d "
724                                                         "of AttributeDescription %s",
725                                                         pretty ? "prettify" : "validate",
726                                                         at->bam_ad->ad_cname.bv_val,
727                                                         k - oldcount );
728                                         Debug( LDAP_DEBUG_TRACE,
729                                                 "==>backsql_get_attr_vals(\"%s\"): "
730                                                 "%s (%d)\n",
731                                                 bsi->bsi_e->e_name.bv_val, buf, retval );
732                                         continue;
733                                 }
734 #endif /* BACKSQL_PRETTY_VALIDATE */
735
736 #ifndef BACKSQL_COUNTQUERY
737                                 (void)backsql_entry_addattr( bsi->bsi_e, 
738                                                 at->bam_ad, &bv,
739                                                 bsi->bsi_op->o_tmpmemctx );
740
741 #else /* BACKSQL_COUNTQUERY */
742                                 if ( normfunc ) {
743                                         struct berval   nbv;
744
745                                         retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
746                                                 at->bam_ad->ad_type->sat_syntax,
747                                                 at->bam_ad->ad_type->sat_equality,
748                                                 &bv, &nbv,
749                                                 bsi->bsi_op->o_tmpmemctx );
750
751                                         if ( retval != LDAP_SUCCESS ) {
752                                                 char    buf[ SLAP_TEXT_BUFLEN ];
753
754                                                 /* FIXME: we're ignoring invalid values,
755                                                  * but we're accepting the attributes;
756                                                  * should we fail at all? */
757                                                 snprintf( buf, sizeof( buf ),
758                                                         "unable to normalize value #%d "
759                                                         "of AttributeDescription %s",
760                                                         at->bam_ad->ad_cname.bv_val,
761                                                         k - oldcount );
762                                                 Debug( LDAP_DEBUG_TRACE,
763                                                         "==>backsql_get_attr_vals(\"%s\"): "
764                                                         "%s (%d)\n",
765                                                         bsi->bsi_e->e_name.bv_val, buf, retval );
766
767 #ifdef BACKSQL_PRETTY_VALIDATE
768                                                 if ( pretty ) {
769                                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
770                                                                         bsi->bsi_op->o_tmpmemctx );
771                                                 }
772 #endif /* BACKSQL_PRETTY_VALIDATE */
773
774                                                 continue;
775                                         }
776                                         ber_dupbv( &attr->a_nvals[ j ], &nbv );
777                                         bsi->bsi_op->o_tmpfree( nbv.bv_val,
778                                                         bsi->bsi_op->o_tmpmemctx );
779                                 }
780
781                                 ber_dupbv( &attr->a_vals[ j ], &bv );
782
783                                 assert( j < oldcount + count );
784                                 j++;
785 #endif /* BACKSQL_COUNTQUERY */
786
787 #ifdef BACKSQL_PRETTY_VALIDATE
788                                 if ( pretty ) {
789                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
790                                                         bsi->bsi_op->o_tmpmemctx );
791                                 }
792 #endif /* BACKSQL_PRETTY_VALIDATE */
793
794 #ifdef BACKSQL_TRACE
795                                 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
796                                         (int)row.col_prec[ i ], 0, 0 );
797
798                         } else {
799                                 Debug( LDAP_DEBUG_TRACE, "NULL value "
800                                         "in this row for attribute \"%s\"\n",
801                                         row.col_names[ i ].bv_val, 0, 0 );
802 #endif /* BACKSQL_TRACE */
803                         }
804                 }
805         }
806
807         backsql_FreeRow( &row );
808         SQLFreeStmt( sth, SQL_DROP );
809         Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
810
811         if ( at->bam_next ) {
812                 return backsql_get_attr_vals( at->bam_next, v_bsi );
813         }
814
815         return 1;
816 }
817
818 int
819 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
820 {
821         Operation               *op = bsi->bsi_op;
822         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
823         int                     i;
824         int                     rc;
825
826         Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
827
828         assert( bsi->bsi_e );
829
830         memset( bsi->bsi_e, 0, sizeof( Entry ) );
831
832         if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
833                 Entry   *e;
834
835                 e = entry_dup( bi->sql_baseObject );
836                 if ( e == NULL ) {
837                         return LDAP_NO_MEMORY;
838                 }
839                         
840                 *bsi->bsi_e = *e;
841                 free( e );
842                 goto done;
843         }
844
845         ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
846         ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
847
848         bsi->bsi_e->e_attrs = NULL;
849         bsi->bsi_e->e_private = NULL;
850
851         bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
852                         eid->eid_oc_id );
853         bsi->bsi_c_eid = eid;
854
855 #ifndef BACKSQL_ARBITRARY_KEY   
856         /* FIXME: unused */
857         bsi->bsi_e->e_id = eid->eid_id;
858 #endif /* ! BACKSQL_ARBITRARY_KEY */
859  
860         rc = attr_merge_normalize_one( bsi->bsi_e,
861                         slap_schema.si_ad_objectClass,
862                         &bsi->bsi_oc->bom_oc->soc_cname,
863                         bsi->bsi_op->o_tmpmemctx );
864         if ( rc != LDAP_SUCCESS ) {
865                 backsql_entry_clean( op, bsi->bsi_e );
866                 return rc;
867         }
868
869         if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
870         {
871                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
872                         "retrieving all attributes\n", 0, 0, 0 );
873                 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
874                                 bsi, 0, AVL_INORDER );
875
876         } else {
877                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
878                         "custom attribute list\n", 0, 0, 0 );
879                 for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
880                         backsql_at_map_rec      **vat;
881                         AttributeName           *an = &bsi->bsi_attrs[ i ];
882                         int                     j;
883
884                         /* if one of the attributes listed here is
885                          * a subtype of another, it must be ignored,
886                          * because subtypes are already dealt with
887                          * by backsql_supad2at()
888                          */
889                         for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
890                                 /* skip self */
891                                 if ( j == i ) {
892                                         continue;
893                                 }
894
895                                 /* skip subtypes */
896                                 if ( is_at_subtype( an->an_desc->ad_type,
897                                                         bsi->bsi_attrs[ j ].an_desc->ad_type ) )
898                                 {
899                                         goto next;
900                                 }
901                         }
902
903                         rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
904                         if ( rc != 0 || vat == NULL ) {
905                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
906                                                 "attribute \"%s\" is not defined "
907                                                 "for objectlass \"%s\"\n",
908                                                 an->an_name.bv_val, 
909                                                 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
910                                 continue;
911                         }
912
913                         for ( j = 0; vat[j]; j++ ) {
914                                 backsql_get_attr_vals( vat[j], bsi );
915                         }
916
917                         ch_free( vat );
918
919 next:;
920                 }
921         }
922
923         if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
924                 Attribute       *a_entryUUID,
925                                 **ap;
926
927                 a_entryUUID = backsql_operational_entryUUID( bi, eid );
928                 if ( a_entryUUID != NULL ) {
929                         for ( ap = &bsi->bsi_e->e_attrs; 
930                                         *ap; 
931                                         ap = &(*ap)->a_next );
932
933                         *ap = a_entryUUID;
934                 }
935         }
936
937         if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
938                         || an_find( bsi->bsi_attrs, &AllOper )
939                         || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
940         {
941                 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
942                         Attribute       *a;
943                         const char      *text = NULL;
944                         char            textbuf[ 1024 ];
945                         size_t          textlen = sizeof( textbuf );
946                         struct berval   soc,
947                                         bv[ 2 ],
948                                         *nvals;
949                         int             rc = LDAP_SUCCESS;
950
951                         a = attr_find( bsi->bsi_e->e_attrs,
952                                         slap_schema.si_ad_objectClass );
953                         if ( a != NULL ) {
954                                 nvals = a->a_nvals;
955
956                         } else {
957                                 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
958                                 BER_BVZERO( &bv[ 1 ] );
959                                 nvals = bv;
960                         }
961
962                         rc = structural_class( nvals, &soc, NULL, 
963                                         &text, textbuf, textlen );
964                         if ( rc != LDAP_SUCCESS ) {
965                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
966                                         "structural_class() failed %d (%s)\n",
967                                         bsi->bsi_e->e_name.bv_val,
968                                         rc, text ? text : "" );
969                                 backsql_entry_clean( op, bsi->bsi_e );
970                                 return rc;
971                         }
972
973                         if ( !bvmatch( &soc, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
974                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
975                                         "computed structuralObjectClass %s "
976                                         "does not match objectClass %s associated "
977                                         "to entry\n",
978                                         bsi->bsi_e->e_name.bv_val, soc.bv_val,
979                                         bsi->bsi_oc->bom_oc->soc_cname.bv_val );
980                                 backsql_entry_clean( op, bsi->bsi_e );
981                                 return rc;
982                         }
983                 }
984
985                 rc = attr_merge_normalize_one( bsi->bsi_e,
986                                 slap_schema.si_ad_structuralObjectClass,
987                                 &bsi->bsi_oc->bom_oc->soc_cname,
988                                 bsi->bsi_op->o_tmpmemctx );
989                 if ( rc != LDAP_SUCCESS ) {
990                         backsql_entry_clean( op, bsi->bsi_e );
991                         return rc;
992                 }
993         }
994
995 done:;
996         Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
997
998         return LDAP_SUCCESS;
999 }
1000