]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/entry-id.c
quick fix for ITS#6616; root cause not clear yet
[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-2010 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         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
536                 "oc=\"%s\" attr=\"%s\" keyval=" BACKSQL_IDFMT "\n",
537                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
538                 BACKSQL_IDARG(bsi->bsi_c_eid->eid_keyval) );
539
540 #ifdef BACKSQL_PRETTY_VALIDATE
541         validate = at->bam_true_ad->ad_type->sat_syntax->ssyn_validate;
542         pretty =  at->bam_true_ad->ad_type->sat_syntax->ssyn_pretty;
543
544         if ( validate == NULL && pretty == NULL ) {
545                 return 1;
546         }
547 #endif /* BACKSQL_PRETTY_VALIDATE */
548
549 #ifdef BACKSQL_COUNTQUERY
550         if ( at->bam_true_ad->ad_type->sat_equality ) {
551                 normfunc = at->bam_true_ad->ad_type->sat_equality->smr_normalize;
552         }
553
554         /* Count how many rows will be returned. This avoids memory 
555          * fragmentation that can result from loading the values in 
556          * one by one and using realloc() 
557          */
558         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 );
559         if ( rc != SQL_SUCCESS ) {
560                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
561                         "error preparing count query: %s\n",
562                         at->bam_countquery, 0, 0 );
563                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
564                 return 1;
565         }
566
567         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
568                         &bsi->bsi_c_eid->eid_keyval );
569         if ( rc != SQL_SUCCESS ) {
570                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
571                         "error binding key value parameter\n", 0, 0, 0 );
572                 SQLFreeStmt( sth, SQL_DROP );
573                 return 1;
574         }
575
576         rc = SQLExecute( sth );
577         if ( ! BACKSQL_SUCCESS( rc ) ) {
578                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
579                         "error executing attribute count query '%s'\n",
580                         at->bam_countquery, 0, 0 );
581                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
582                 SQLFreeStmt( sth, SQL_DROP );
583                 return 1;
584         }
585
586         SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG,
587                         (SQLPOINTER)&count,
588                         (SQLINTEGER)sizeof( count ),
589                         &countsize );
590
591         rc = SQLFetch( sth );
592         if ( rc != SQL_SUCCESS ) {
593                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
594                         "error fetch results of count query: %s\n",
595                         at->bam_countquery, 0, 0 );
596                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
597                 SQLFreeStmt( sth, SQL_DROP );
598                 return 1;
599         }
600
601         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
602                 "number of values in query: %u\n", count, 0, 0 );
603         SQLFreeStmt( sth, SQL_DROP );
604         if ( count == 0 ) {
605                 return 1;
606         }
607
608         attr = attr_find( bsi->bsi_e->e_attrs, at->bam_true_ad );
609         if ( attr != NULL ) {
610                 BerVarray       tmp;
611
612                 if ( attr->a_vals != NULL ) {
613                         oldcount = attr->a_numvals;
614                 }
615
616                 tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
617                 if ( tmp == NULL ) {
618                         return 1;
619                 }
620                 attr->a_vals = tmp;
621                 memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
622
623                 if ( normfunc ) {
624                         tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
625                         if ( tmp == NULL ) {
626                                 return 1;
627                         }
628                         attr->a_nvals = tmp;
629                         memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
630
631                 } else {
632                         attr->a_nvals = attr->a_vals;
633                 }
634                 attr->a_numvals += count;
635
636         } else {
637                 append = 1;
638
639                 /* Make space for the array of values */
640                 attr = attr_alloc( at->bam_true_ad );
641                 attr->a_numvals = count;
642                 attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
643                 if ( attr->a_vals == NULL ) {
644                         Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
645                         ch_free( attr );
646                         return 1;
647                 }
648                 if ( normfunc ) {
649                         attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
650                         if ( attr->a_nvals == NULL ) {
651                                 ch_free( attr->a_vals );
652                                 ch_free( attr );
653                                 return 1;
654
655                         }
656
657                 } else {
658                         attr->a_nvals = attr->a_vals;
659                 }
660         }
661 #endif /* BACKSQL_COUNTQUERY */
662
663         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
664         if ( rc != SQL_SUCCESS ) {
665                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
666                         "error preparing query: %s\n", at->bam_query, 0, 0 );
667                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
668 #ifdef BACKSQL_COUNTQUERY
669                 if ( append ) {
670                         attr_free( attr );
671                 }
672 #endif /* BACKSQL_COUNTQUERY */
673                 return 1;
674         }
675
676         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
677                         &bsi->bsi_c_eid->eid_keyval );
678         if ( rc != SQL_SUCCESS ) {
679                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
680                         "error binding key value parameter\n", 0, 0, 0 );
681 #ifdef BACKSQL_COUNTQUERY
682                 if ( append ) {
683                         attr_free( attr );
684                 }
685 #endif /* BACKSQL_COUNTQUERY */
686                 return 1;
687         }
688
689 #ifdef BACKSQL_TRACE
690         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
691                 "query=\"%s\" keyval=" BACKSQL_IDFMT "\n", at->bam_query,
692                 BACKSQL_IDARG(bsi->bsi_c_eid->eid_keyval), 0 );
693 #endif /* BACKSQL_TRACE */
694
695         rc = SQLExecute( sth );
696         if ( ! BACKSQL_SUCCESS( rc ) ) {
697                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
698                         "error executing attribute query \"%s\"\n",
699                         at->bam_query, 0, 0 );
700                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
701                 SQLFreeStmt( sth, SQL_DROP );
702 #ifdef BACKSQL_COUNTQUERY
703                 if ( append ) {
704                         attr_free( attr );
705                 }
706 #endif /* BACKSQL_COUNTQUERY */
707                 return 1;
708         }
709
710         backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
711 #ifdef BACKSQL_COUNTQUERY
712         j = oldcount;
713 #endif /* BACKSQL_COUNTQUERY */
714         for ( rc = SQLFetch( sth ), k = 0;
715                         BACKSQL_SUCCESS( rc );
716                         rc = SQLFetch( sth ), k++ )
717         {
718                 for ( i = 0; i < (unsigned long)row.ncols; i++ ) {
719
720                         if ( row.value_len[ i ] > 0 ) {
721                                 struct berval           bv;
722                                 int                     retval;
723 #ifdef BACKSQL_TRACE
724                                 AttributeDescription    *ad = NULL;
725                                 const char              *text;
726
727                                 retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
728                                 if ( retval != LDAP_SUCCESS ) {
729                                         Debug( LDAP_DEBUG_ANY,
730                                                 "==>backsql_get_attr_vals(\"%s\"): "
731                                                 "unable to find AttributeDescription %s "
732                                                 "in schema (%d)\n",
733                                                 bsi->bsi_e->e_name.bv_val,
734                                                 row.col_names[ i ].bv_val, retval );
735                                         res = 1;
736                                         goto done;
737                                 }
738
739                                 if ( ad != at->bam_ad ) {
740                                         Debug( LDAP_DEBUG_ANY,
741                                                 "==>backsql_get_attr_vals(\"%s\"): "
742                                                 "column name %s differs from "
743                                                 "AttributeDescription %s\n",
744                                                 bsi->bsi_e->e_name.bv_val,
745                                                 ad->ad_cname.bv_val,
746                                                 at->bam_ad->ad_cname.bv_val );
747                                         res = 1;
748                                         goto done;
749                                 }
750 #endif /* BACKSQL_TRACE */
751
752                                 /* ITS#3386, ITS#3113 - 20070308
753                                  * If a binary is fetched?
754                                  * must use the actual size read
755                                  * from the database.
756                                  */
757                                 if ( BACKSQL_IS_BINARY( row.col_type[ i ] ) ) {
758 #ifdef BACKSQL_TRACE
759                                         Debug( LDAP_DEBUG_ANY,
760                                                 "==>backsql_get_attr_vals(\"%s\"): "
761                                                 "column name %s: data is binary; "
762                                                 "using database size %ld\n",
763                                                 bsi->bsi_e->e_name.bv_val,
764                                                 ad->ad_cname.bv_val,
765                                                 row.value_len[ i ] );
766 #endif /* BACKSQL_TRACE */
767                                         bv.bv_val = row.cols[ i ];
768                                         bv.bv_len = row.value_len[ i ];
769
770                                 } else {
771                                         ber_str2bv( row.cols[ i ], 0, 0, &bv );
772                                 }
773
774 #ifdef BACKSQL_PRETTY_VALIDATE
775                                 if ( pretty ) {
776                                         struct berval   pbv;
777
778                                         retval = pretty( at->bam_true_ad->ad_type->sat_syntax,
779                                                 &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
780                                         bv = pbv;
781
782                                 } else {
783                                         retval = validate( at->bam_true_ad->ad_type->sat_syntax,
784                                                 &bv );
785                                 }
786
787                                 if ( retval != LDAP_SUCCESS ) {
788                                         char    buf[ SLAP_TEXT_BUFLEN ];
789
790                                         /* FIXME: we're ignoring invalid values,
791                                          * but we're accepting the attributes;
792                                          * should we fail at all? */
793                                         snprintf( buf, sizeof( buf ),
794                                                         "unable to %s value #%lu "
795                                                         "of AttributeDescription %s",
796                                                         pretty ? "prettify" : "validate",
797                                                         k - oldcount,
798                                                         at->bam_ad->ad_cname.bv_val );
799                                         Debug( LDAP_DEBUG_TRACE,
800                                                 "==>backsql_get_attr_vals(\"%s\"): "
801                                                 "%s (%d)\n",
802                                                 bsi->bsi_e->e_name.bv_val, buf, retval );
803                                         continue;
804                                 }
805 #endif /* BACKSQL_PRETTY_VALIDATE */
806
807 #ifndef BACKSQL_COUNTQUERY
808                                 (void)backsql_entry_addattr( bsi->bsi_e, 
809                                                 at->bam_true_ad, &bv,
810                                                 bsi->bsi_op->o_tmpmemctx );
811
812 #else /* BACKSQL_COUNTQUERY */
813                                 if ( normfunc ) {
814                                         struct berval   nbv;
815
816                                         retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
817                                                 at->bam_true_ad->ad_type->sat_syntax,
818                                                 at->bam_true_ad->ad_type->sat_equality,
819                                                 &bv, &nbv,
820                                                 bsi->bsi_op->o_tmpmemctx );
821
822                                         if ( retval != LDAP_SUCCESS ) {
823                                                 char    buf[ SLAP_TEXT_BUFLEN ];
824
825                                                 /* FIXME: we're ignoring invalid values,
826                                                  * but we're accepting the attributes;
827                                                  * should we fail at all? */
828                                                 snprintf( buf, sizeof( buf ),
829                                                         "unable to normalize value #%lu "
830                                                         "of AttributeDescription %s",
831                                                         k - oldcount,
832                                                         at->bam_ad->ad_cname.bv_val );
833                                                 Debug( LDAP_DEBUG_TRACE,
834                                                         "==>backsql_get_attr_vals(\"%s\"): "
835                                                         "%s (%d)\n",
836                                                         bsi->bsi_e->e_name.bv_val, buf, retval );
837
838 #ifdef BACKSQL_PRETTY_VALIDATE
839                                                 if ( pretty ) {
840                                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
841                                                                         bsi->bsi_op->o_tmpmemctx );
842                                                 }
843 #endif /* BACKSQL_PRETTY_VALIDATE */
844
845                                                 continue;
846                                         }
847                                         ber_dupbv( &attr->a_nvals[ j ], &nbv );
848                                         bsi->bsi_op->o_tmpfree( nbv.bv_val,
849                                                         bsi->bsi_op->o_tmpmemctx );
850                                 }
851
852                                 ber_dupbv( &attr->a_vals[ j ], &bv );
853
854                                 assert( j < oldcount + count );
855                                 j++;
856 #endif /* BACKSQL_COUNTQUERY */
857
858 #ifdef BACKSQL_PRETTY_VALIDATE
859                                 if ( pretty ) {
860                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
861                                                         bsi->bsi_op->o_tmpmemctx );
862                                 }
863 #endif /* BACKSQL_PRETTY_VALIDATE */
864
865 #ifdef BACKSQL_TRACE
866                                 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
867                                         (int)row.col_prec[ i ], 0, 0 );
868
869                         } else {
870                                 Debug( LDAP_DEBUG_TRACE, "NULL value "
871                                         "in this row for attribute \"%s\"\n",
872                                         row.col_names[ i ].bv_val, 0, 0 );
873 #endif /* BACKSQL_TRACE */
874                         }
875                 }
876         }
877
878 #ifdef BACKSQL_COUNTQUERY
879         if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
880                 /* don't leave around attributes with no values */
881                 attr_free( attr );
882
883         } else if ( append ) {
884                 Attribute       **ap;
885
886                 for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
887                         /* goto last */ ;
888                 *ap =  attr;
889         }
890 #endif /* BACKSQL_COUNTQUERY */
891
892         SQLFreeStmt( sth, SQL_DROP );
893         Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
894
895         if ( at->bam_next ) {
896                 res = backsql_get_attr_vals( at->bam_next, v_bsi );
897         } else {
898                 res = 1;
899         }
900
901 #ifdef BACKSQL_TRACE
902 done:;
903 #endif /* BACKSQL_TRACE */
904         backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
905
906         return res;
907 }
908
909 int
910 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
911 {
912         Operation               *op = bsi->bsi_op;
913         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
914         int                     i;
915         int                     rc;
916
917         Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
918
919         assert( bsi->bsi_e != NULL );
920
921         memset( bsi->bsi_e, 0, sizeof( Entry ) );
922
923         if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
924                 (void)entry_dup2( bsi->bsi_e, bi->sql_baseObject );
925                 goto done;
926         }
927
928         bsi->bsi_e->e_attrs = NULL;
929         bsi->bsi_e->e_private = NULL;
930
931         if ( eid->eid_oc == NULL ) {
932                 eid->eid_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
933                         eid->eid_oc_id );
934                 if ( eid->eid_oc == NULL ) {
935                         Debug( LDAP_DEBUG_TRACE,
936                                 "backsql_id2entry(): unable to fetch objectClass with id=%lu for entry id=" BACKSQL_IDFMT " dn=\"%s\"\n",
937                                 eid->eid_oc_id, BACKSQL_IDARG(eid->eid_id),
938                                 eid->eid_dn.bv_val );
939                         return LDAP_OTHER;
940                 }
941         }
942         bsi->bsi_oc = eid->eid_oc;
943         bsi->bsi_c_eid = eid;
944
945         ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
946         ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
947
948 #ifndef BACKSQL_ARBITRARY_KEY   
949         /* FIXME: unused */
950         bsi->bsi_e->e_id = eid->eid_id;
951 #endif /* ! BACKSQL_ARBITRARY_KEY */
952  
953         rc = attr_merge_normalize_one( bsi->bsi_e,
954                         slap_schema.si_ad_objectClass,
955                         &bsi->bsi_oc->bom_oc->soc_cname,
956                         bsi->bsi_op->o_tmpmemctx );
957         if ( rc != LDAP_SUCCESS ) {
958                 backsql_entry_clean( op, bsi->bsi_e );
959                 return rc;
960         }
961
962         if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
963         {
964                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
965                         "retrieving all attributes\n", 0, 0, 0 );
966                 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
967                                 bsi, 0, AVL_INORDER );
968
969         } else {
970                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
971                         "custom attribute list\n", 0, 0, 0 );
972                 for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
973                         backsql_at_map_rec      **vat;
974                         AttributeName           *an = &bsi->bsi_attrs[ i ];
975                         int                     j;
976
977                         /* if one of the attributes listed here is
978                          * a subtype of another, it must be ignored,
979                          * because subtypes are already dealt with
980                          * by backsql_supad2at()
981                          */
982                         for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
983                                 /* skip self */
984                                 if ( j == i ) {
985                                         continue;
986                                 }
987
988                                 /* skip subtypes */
989                                 if ( is_at_subtype( an->an_desc->ad_type,
990                                                         bsi->bsi_attrs[ j ].an_desc->ad_type ) )
991                                 {
992                                         goto next;
993                                 }
994                         }
995
996                         rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
997                         if ( rc != 0 || vat == NULL ) {
998                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
999                                                 "attribute \"%s\" is not defined "
1000                                                 "for objectlass \"%s\"\n",
1001                                                 an->an_name.bv_val, 
1002                                                 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
1003                                 continue;
1004                         }
1005
1006                         for ( j = 0; vat[j]; j++ ) {
1007                                 backsql_get_attr_vals( vat[j], bsi );
1008                         }
1009
1010                         ch_free( vat );
1011
1012 next:;
1013                 }
1014         }
1015
1016         if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
1017                 Attribute       *a_entryUUID,
1018                                 **ap;
1019
1020                 a_entryUUID = backsql_operational_entryUUID( bi, eid );
1021                 if ( a_entryUUID != NULL ) {
1022                         for ( ap = &bsi->bsi_e->e_attrs; 
1023                                         *ap; 
1024                                         ap = &(*ap)->a_next );
1025
1026                         *ap = a_entryUUID;
1027                 }
1028         }
1029
1030         if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
1031                         || an_find( bsi->bsi_attrs, slap_bv_all_operational_attrs )
1032                         || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
1033         {
1034                 ObjectClass     *soc = NULL;
1035
1036                 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
1037                         Attribute       *a;
1038                         const char      *text = NULL;
1039                         char            textbuf[ 1024 ];
1040                         size_t          textlen = sizeof( textbuf );
1041                         struct berval   bv[ 2 ],
1042                                         *nvals;
1043                         int             rc = LDAP_SUCCESS;
1044
1045                         a = attr_find( bsi->bsi_e->e_attrs,
1046                                         slap_schema.si_ad_objectClass );
1047                         if ( a != NULL ) {
1048                                 nvals = a->a_nvals;
1049
1050                         } else {
1051                                 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
1052                                 BER_BVZERO( &bv[ 1 ] );
1053                                 nvals = bv;
1054                         }
1055
1056                         rc = structural_class( nvals, &soc, NULL, 
1057                                         &text, textbuf, textlen, op->o_tmpmemctx );
1058                         if ( rc != LDAP_SUCCESS ) {
1059                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1060                                         "structural_class() failed %d (%s)\n",
1061                                         bsi->bsi_e->e_name.bv_val,
1062                                         rc, text ? text : "" );
1063                                 backsql_entry_clean( op, bsi->bsi_e );
1064                                 return rc;
1065                         }
1066
1067                         if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
1068                                 if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) {
1069                                         Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1070                                                 "computed structuralObjectClass %s "
1071                                                 "does not match objectClass %s associated "
1072                                                 "to entry\n",
1073                                                 bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
1074                                                 bsi->bsi_oc->bom_oc->soc_cname.bv_val );
1075                                         backsql_entry_clean( op, bsi->bsi_e );
1076                                         return rc;
1077                                 }
1078
1079                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1080                                         "computed structuralObjectClass %s "
1081                                         "is subclass of objectClass %s associated "
1082                                         "to entry\n",
1083                                         bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
1084                                         bsi->bsi_oc->bom_oc->soc_cname.bv_val );
1085                         }
1086
1087                 } else {
1088                         soc = bsi->bsi_oc->bom_oc;
1089                 }
1090
1091                 rc = attr_merge_normalize_one( bsi->bsi_e,
1092                                 slap_schema.si_ad_structuralObjectClass,
1093                                 &soc->soc_cname,
1094                                 bsi->bsi_op->o_tmpmemctx );
1095                 if ( rc != LDAP_SUCCESS ) {
1096                         backsql_entry_clean( op, bsi->bsi_e );
1097                         return rc;
1098                 }
1099         }
1100
1101 done:;
1102         Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
1103
1104         return LDAP_SUCCESS;
1105 }
1106