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