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