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