]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/entry-id.c
update for new backend types
[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 != NULL );
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 != NULL );
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 != NULL );
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                                 append = 0;
464         Attribute               *attr = NULL;
465
466         slap_mr_normalize_func          *normfunc = NULL;
467 #endif /* BACKSQL_COUNTQUERY */
468 #ifdef BACKSQL_PRETTY_VALIDATE
469         slap_syntax_validate_func       *validate = NULL;
470         slap_syntax_transform_func      *pretty = NULL;
471 #endif /* BACKSQL_PRETTY_VALIDATE */
472
473         assert( at != NULL );
474         assert( bsi != NULL );
475
476 #ifdef BACKSQL_ARBITRARY_KEY
477         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
478                 "oc=\"%s\" attr=\"%s\" keyval=%s\n",
479                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
480                 bsi->bsi_c_eid->eid_keyval.bv_val );
481 #else /* ! BACKSQL_ARBITRARY_KEY */
482         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
483                 "oc=\"%s\" attr=\"%s\" keyval=%ld\n",
484                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
485                 bsi->bsi_c_eid->eid_keyval );
486 #endif /* ! BACKSQL_ARBITRARY_KEY */
487
488 #ifdef BACKSQL_PRETTY_VALIDATE
489         validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate;
490         pretty =  at->bam_ad->ad_type->sat_syntax->ssyn_pretty;
491
492         if ( validate == NULL && pretty == NULL ) {
493                 return 1;
494         }
495 #endif /* BACKSQL_PRETTY_VALIDATE */
496
497 #ifdef BACKSQL_COUNTQUERY
498         if ( at->bam_ad->ad_type->sat_equality ) {
499                 normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize;
500         }
501
502         /* Count how many rows will be returned. This avoids memory 
503          * fragmentation that can result from loading the values in 
504          * one by one and using realloc() 
505          */
506         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 );
507         if ( rc != SQL_SUCCESS ) {
508                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
509                         "error preparing count query: %s\n",
510                         at->bam_countquery, 0, 0 );
511                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
512                 return 1;
513         }
514
515         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
516                         &bsi->bsi_c_eid->eid_keyval );
517         if ( rc != SQL_SUCCESS ) {
518                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
519                         "error binding key value parameter\n", 0, 0, 0 );
520                 SQLFreeStmt( sth, SQL_DROP );
521                 return 1;
522         }
523
524         rc = SQLExecute( sth );
525         if ( ! BACKSQL_SUCCESS( rc ) ) {
526                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
527                         "error executing attribute count query '%s'\n",
528                         at->bam_countquery, 0, 0 );
529                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
530                 SQLFreeStmt( sth, SQL_DROP );
531                 return 1;
532         }
533
534         SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG,
535                         (SQLPOINTER)&count,
536                         (SQLINTEGER)sizeof( count ),
537                         &countsize );
538
539         rc = SQLFetch( sth );
540         if ( rc != SQL_SUCCESS ) {
541                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
542                         "error fetch results of count query: %s\n",
543                         at->bam_countquery, 0, 0 );
544                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
545                 SQLFreeStmt( sth, SQL_DROP );
546                 return 1;
547         }
548
549         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
550                 "number of values in query: %d\n", count, 0, 0 );
551         SQLFreeStmt( sth, SQL_DROP );
552         if ( count == 0 ) {
553                 return 1;
554         }
555
556         attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad );
557         if ( attr != NULL ) {
558                 BerVarray       tmp;
559
560                 if ( attr->a_vals != NULL ) {
561                         for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ )
562                                 /* just count */ ;
563                 }
564
565                 tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
566                 if ( tmp == NULL ) {
567                         return 1;
568                 }
569                 attr->a_vals = tmp;
570                 memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
571
572                 if ( normfunc ) {
573                         tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
574                         if ( tmp == NULL ) {
575                                 return 1;
576                         }
577                         attr->a_nvals = tmp;
578                         memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
579
580                 } else {
581                         attr->a_nvals = attr->a_vals;
582                 }
583
584         } else {
585                 append = 1;
586
587                 /* Make space for the array of values */
588                 attr = (Attribute *) ch_malloc( sizeof( Attribute ) );
589                 attr->a_desc = at->bam_ad;
590                 attr->a_flags = 0;
591                 attr->a_next = NULL;
592                 attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
593                 if ( attr->a_vals == NULL ) {
594                         Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
595                         ch_free( attr );
596                         return 1;
597                 }
598                 memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) );
599                 if ( normfunc ) {
600                         attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
601                         if ( attr->a_nvals == NULL ) {
602                                 ch_free( attr->a_vals );
603                                 ch_free( attr );
604                                 return 1;
605
606                         } else {
607                                 memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) );
608                         }
609
610                 } else {
611                         attr->a_nvals = attr->a_vals;
612                 }
613         }
614 #endif /* BACKSQL_COUNTQUERY */
615
616         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
617         if ( rc != SQL_SUCCESS ) {
618                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
619                         "error preparing query: %s\n", at->bam_query, 0, 0 );
620                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
621                 return 1;
622         }
623
624         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
625                         &bsi->bsi_c_eid->eid_keyval );
626         if ( rc != SQL_SUCCESS ) {
627                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
628                         "error binding key value parameter\n", 0, 0, 0 );
629                 return 1;
630         }
631
632 #ifdef BACKSQL_TRACE
633 #ifdef BACKSQL_ARBITRARY_KEY
634         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
635                 "query=\"%s\" keyval=%s\n", at->bam_query,
636                 bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
637 #else /* !BACKSQL_ARBITRARY_KEY */
638         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
639                 "query=\"%s\" keyval=%d\n", at->bam_query,
640                 bsi->bsi_c_eid->eid_keyval, 0 );
641 #endif /* ! BACKSQL_ARBITRARY_KEY */
642 #endif /* BACKSQL_TRACE */
643
644         rc = SQLExecute( sth );
645         if ( ! BACKSQL_SUCCESS( rc ) ) {
646                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
647                         "error executing attribute query \"%s\"\n",
648                         at->bam_query, 0, 0 );
649                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
650                 SQLFreeStmt( sth, SQL_DROP );
651                 return 1;
652         }
653
654         backsql_BindRowAsStrings( sth, &row );
655 #ifdef BACKSQL_COUNTQUERY
656         j = oldcount;
657 #endif /* BACKSQL_COUNTQUERY */
658         for ( rc = SQLFetch( sth ), k = 0;
659                         BACKSQL_SUCCESS( rc );
660                         rc = SQLFetch( sth ), k++ )
661         {
662                 for ( i = 0; i < row.ncols; i++ ) {
663
664                         if ( row.value_len[ i ] > 0 ) {
665                                 struct berval           bv;
666                                 int                     retval;
667 #ifdef BACKSQL_TRACE
668                                 AttributeDescription    *ad = NULL;
669                                 const char              *text;
670
671                                 retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
672                                 if ( retval != LDAP_SUCCESS ) {
673                                         Debug( LDAP_DEBUG_ANY,
674                                                 "==>backsql_get_attr_vals(\"%s\"): "
675                                                 "unable to find AttributeDescription %s "
676                                                 "in schema (%d)\n",
677                                                 bsi->bsi_e->e_name.bv_val,
678                                                 row.col_names[ i ].bv_val, retval );
679                                         return 1;
680                                 }
681
682                                 if ( ad != at->bam_ad ) {
683                                         Debug( LDAP_DEBUG_ANY,
684                                                 "==>backsql_get_attr_vals(\"%s\"): "
685                                                 "column name %s differs from "
686                                                 "AttributeDescription %s\n",
687                                                 bsi->bsi_e->e_name.bv_val,
688                                                 ad->ad_cname.bv_val,
689                                                 at->bam_ad->ad_cname.bv_val );
690                                         return 1;
691                                 }
692 #endif /* BACKSQL_TRACE */
693
694                                 /*
695                                  * FIXME: what if a binary 
696                                  * is fetched?
697                                  */
698                                 ber_str2bv( row.cols[ i ], 0, 0, &bv );
699
700 #ifdef BACKSQL_PRETTY_VALIDATE
701                                 if ( pretty ) {
702                                         struct berval   pbv;
703
704                                         retval = pretty( at->bam_ad->ad_type->sat_syntax,
705                                                 &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
706                                         bv = pbv;
707
708                                 } else {
709                                         retval = validate( at->bam_ad->ad_type->sat_syntax,
710                                                 &bv );
711                                 }
712
713                                 if ( retval != LDAP_SUCCESS ) {
714                                         char    buf[ SLAP_TEXT_BUFLEN ];
715
716                                         /* FIXME: we're ignoring invalid values,
717                                          * but we're accepting the attributes;
718                                          * should we fail at all? */
719                                         snprintf( buf, sizeof( buf ),
720                                                         "unable to %s value #%d "
721                                                         "of AttributeDescription %s",
722                                                         pretty ? "prettify" : "validate",
723                                                         at->bam_ad->ad_cname.bv_val,
724                                                         k - oldcount );
725                                         Debug( LDAP_DEBUG_TRACE,
726                                                 "==>backsql_get_attr_vals(\"%s\"): "
727                                                 "%s (%d)\n",
728                                                 bsi->bsi_e->e_name.bv_val, buf, retval );
729                                         continue;
730                                 }
731 #endif /* BACKSQL_PRETTY_VALIDATE */
732
733 #ifndef BACKSQL_COUNTQUERY
734                                 (void)backsql_entry_addattr( bsi->bsi_e, 
735                                                 at->bam_ad, &bv,
736                                                 bsi->bsi_op->o_tmpmemctx );
737
738 #else /* BACKSQL_COUNTQUERY */
739                                 if ( normfunc ) {
740                                         struct berval   nbv;
741
742                                         retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
743                                                 at->bam_ad->ad_type->sat_syntax,
744                                                 at->bam_ad->ad_type->sat_equality,
745                                                 &bv, &nbv,
746                                                 bsi->bsi_op->o_tmpmemctx );
747
748                                         if ( retval != LDAP_SUCCESS ) {
749                                                 char    buf[ SLAP_TEXT_BUFLEN ];
750
751                                                 /* FIXME: we're ignoring invalid values,
752                                                  * but we're accepting the attributes;
753                                                  * should we fail at all? */
754                                                 snprintf( buf, sizeof( buf ),
755                                                         "unable to normalize value #%d "
756                                                         "of AttributeDescription %s",
757                                                         at->bam_ad->ad_cname.bv_val,
758                                                         k - oldcount );
759                                                 Debug( LDAP_DEBUG_TRACE,
760                                                         "==>backsql_get_attr_vals(\"%s\"): "
761                                                         "%s (%d)\n",
762                                                         bsi->bsi_e->e_name.bv_val, buf, retval );
763
764 #ifdef BACKSQL_PRETTY_VALIDATE
765                                                 if ( pretty ) {
766                                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
767                                                                         bsi->bsi_op->o_tmpmemctx );
768                                                 }
769 #endif /* BACKSQL_PRETTY_VALIDATE */
770
771                                                 continue;
772                                         }
773                                         ber_dupbv( &attr->a_nvals[ j ], &nbv );
774                                         bsi->bsi_op->o_tmpfree( nbv.bv_val,
775                                                         bsi->bsi_op->o_tmpmemctx );
776                                 }
777
778                                 ber_dupbv( &attr->a_vals[ j ], &bv );
779
780                                 assert( j < oldcount + count );
781                                 j++;
782 #endif /* BACKSQL_COUNTQUERY */
783
784 #ifdef BACKSQL_PRETTY_VALIDATE
785                                 if ( pretty ) {
786                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
787                                                         bsi->bsi_op->o_tmpmemctx );
788                                 }
789 #endif /* BACKSQL_PRETTY_VALIDATE */
790
791 #ifdef BACKSQL_TRACE
792                                 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
793                                         (int)row.col_prec[ i ], 0, 0 );
794
795                         } else {
796                                 Debug( LDAP_DEBUG_TRACE, "NULL value "
797                                         "in this row for attribute \"%s\"\n",
798                                         row.col_names[ i ].bv_val, 0, 0 );
799 #endif /* BACKSQL_TRACE */
800                         }
801                 }
802         }
803
804 #ifdef BACKSQL_COUNTQUERY
805         if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
806                 /* don't leave around attributes with no values */
807                 attr_free( attr );
808
809         } else if ( append ) {
810                 Attribute       **ap;
811
812                 for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
813                         /* goto last */ ;
814                 *ap =  attr;
815         }
816 #endif /* BACKSQL_COUNTQUERY */
817
818         backsql_FreeRow( &row );
819         SQLFreeStmt( sth, SQL_DROP );
820         Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
821
822         if ( at->bam_next ) {
823                 return backsql_get_attr_vals( at->bam_next, v_bsi );
824         }
825
826         return 1;
827 }
828
829 int
830 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
831 {
832         Operation               *op = bsi->bsi_op;
833         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
834         int                     i;
835         int                     rc;
836
837         Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
838
839         assert( bsi->bsi_e != NULL );
840
841         memset( bsi->bsi_e, 0, sizeof( Entry ) );
842
843         if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
844                 Entry   *e;
845
846                 e = entry_dup( bi->sql_baseObject );
847                 if ( e == NULL ) {
848                         return LDAP_NO_MEMORY;
849                 }
850                         
851                 *bsi->bsi_e = *e;
852                 free( e );
853                 goto done;
854         }
855
856         ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
857         ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
858
859         bsi->bsi_e->e_attrs = NULL;
860         bsi->bsi_e->e_private = NULL;
861
862         bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
863                         eid->eid_oc_id );
864         bsi->bsi_c_eid = eid;
865
866 #ifndef BACKSQL_ARBITRARY_KEY   
867         /* FIXME: unused */
868         bsi->bsi_e->e_id = eid->eid_id;
869 #endif /* ! BACKSQL_ARBITRARY_KEY */
870  
871         rc = attr_merge_normalize_one( bsi->bsi_e,
872                         slap_schema.si_ad_objectClass,
873                         &bsi->bsi_oc->bom_oc->soc_cname,
874                         bsi->bsi_op->o_tmpmemctx );
875         if ( rc != LDAP_SUCCESS ) {
876                 backsql_entry_clean( op, bsi->bsi_e );
877                 return rc;
878         }
879
880         if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
881         {
882                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
883                         "retrieving all attributes\n", 0, 0, 0 );
884                 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
885                                 bsi, 0, AVL_INORDER );
886
887         } else {
888                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
889                         "custom attribute list\n", 0, 0, 0 );
890                 for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
891                         backsql_at_map_rec      **vat;
892                         AttributeName           *an = &bsi->bsi_attrs[ i ];
893                         int                     j;
894
895                         /* if one of the attributes listed here is
896                          * a subtype of another, it must be ignored,
897                          * because subtypes are already dealt with
898                          * by backsql_supad2at()
899                          */
900                         for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
901                                 /* skip self */
902                                 if ( j == i ) {
903                                         continue;
904                                 }
905
906                                 /* skip subtypes */
907                                 if ( is_at_subtype( an->an_desc->ad_type,
908                                                         bsi->bsi_attrs[ j ].an_desc->ad_type ) )
909                                 {
910                                         goto next;
911                                 }
912                         }
913
914                         rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
915                         if ( rc != 0 || vat == NULL ) {
916                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
917                                                 "attribute \"%s\" is not defined "
918                                                 "for objectlass \"%s\"\n",
919                                                 an->an_name.bv_val, 
920                                                 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
921                                 continue;
922                         }
923
924                         for ( j = 0; vat[j]; j++ ) {
925                                 backsql_get_attr_vals( vat[j], bsi );
926                         }
927
928                         ch_free( vat );
929
930 next:;
931                 }
932         }
933
934         if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
935                 Attribute       *a_entryUUID,
936                                 **ap;
937
938                 a_entryUUID = backsql_operational_entryUUID( bi, eid );
939                 if ( a_entryUUID != NULL ) {
940                         for ( ap = &bsi->bsi_e->e_attrs; 
941                                         *ap; 
942                                         ap = &(*ap)->a_next );
943
944                         *ap = a_entryUUID;
945                 }
946         }
947
948         if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
949                         || an_find( bsi->bsi_attrs, &AllOper )
950                         || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
951         {
952                 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
953                         Attribute       *a;
954                         const char      *text = NULL;
955                         char            textbuf[ 1024 ];
956                         size_t          textlen = sizeof( textbuf );
957                         struct berval   soc,
958                                         bv[ 2 ],
959                                         *nvals;
960                         int             rc = LDAP_SUCCESS;
961
962                         a = attr_find( bsi->bsi_e->e_attrs,
963                                         slap_schema.si_ad_objectClass );
964                         if ( a != NULL ) {
965                                 nvals = a->a_nvals;
966
967                         } else {
968                                 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
969                                 BER_BVZERO( &bv[ 1 ] );
970                                 nvals = bv;
971                         }
972
973                         rc = structural_class( nvals, &soc, NULL, 
974                                         &text, textbuf, textlen );
975                         if ( rc != LDAP_SUCCESS ) {
976                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
977                                         "structural_class() failed %d (%s)\n",
978                                         bsi->bsi_e->e_name.bv_val,
979                                         rc, text ? text : "" );
980                                 backsql_entry_clean( op, bsi->bsi_e );
981                                 return rc;
982                         }
983
984                         if ( !bvmatch( &soc, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
985                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
986                                         "computed structuralObjectClass %s "
987                                         "does not match objectClass %s associated "
988                                         "to entry\n",
989                                         bsi->bsi_e->e_name.bv_val, soc.bv_val,
990                                         bsi->bsi_oc->bom_oc->soc_cname.bv_val );
991                                 backsql_entry_clean( op, bsi->bsi_e );
992                                 return rc;
993                         }
994                 }
995
996                 rc = attr_merge_normalize_one( bsi->bsi_e,
997                                 slap_schema.si_ad_structuralObjectClass,
998                                 &bsi->bsi_oc->bom_oc->soc_cname,
999                                 bsi->bsi_op->o_tmpmemctx );
1000                 if ( rc != LDAP_SUCCESS ) {
1001                         backsql_entry_clean( op, bsi->bsi_e );
1002                         return rc;
1003                 }
1004         }
1005
1006 done:;
1007         Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
1008
1009         return LDAP_SUCCESS;
1010 }
1011