]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/entry-id.c
b96a41cb148262a59489f22026efd9932f170030
[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_ad->ad_type->sat_syntax->ssyn_validate;
520         pretty =  at->bam_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_ad->ad_type->sat_equality ) {
529                 normfunc = at->bam_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_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 = (Attribute *) ch_malloc( sizeof( Attribute ) );
619                 attr->a_desc = at->bam_ad;
620                 attr->a_flags = 0;
621                 attr->a_next = NULL;
622                 attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
623                 if ( attr->a_vals == NULL ) {
624                         Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
625                         ch_free( attr );
626                         return 1;
627                 }
628                 memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) );
629                 if ( normfunc ) {
630                         attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
631                         if ( attr->a_nvals == NULL ) {
632                                 ch_free( attr->a_vals );
633                                 ch_free( attr );
634                                 return 1;
635
636                         } else {
637                                 memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) );
638                         }
639
640                 } else {
641                         attr->a_nvals = attr->a_vals;
642                 }
643         }
644 #endif /* BACKSQL_COUNTQUERY */
645
646         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
647         if ( rc != SQL_SUCCESS ) {
648                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
649                         "error preparing query: %s\n", at->bam_query, 0, 0 );
650                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
651 #ifdef BACKSQL_COUNTQUERY
652                 if ( append ) {
653                         attr_free( attr );
654                 }
655 #endif /* BACKSQL_COUNTQUERY */
656                 return 1;
657         }
658
659         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
660                         &bsi->bsi_c_eid->eid_keyval );
661         if ( rc != SQL_SUCCESS ) {
662                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
663                         "error binding key value parameter\n", 0, 0, 0 );
664 #ifdef BACKSQL_COUNTQUERY
665                 if ( append ) {
666                         attr_free( attr );
667                 }
668 #endif /* BACKSQL_COUNTQUERY */
669                 return 1;
670         }
671
672 #ifdef BACKSQL_TRACE
673 #ifdef BACKSQL_ARBITRARY_KEY
674         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
675                 "query=\"%s\" keyval=%s\n", at->bam_query,
676                 bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
677 #else /* !BACKSQL_ARBITRARY_KEY */
678         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
679                 "query=\"%s\" keyval=%d\n", at->bam_query,
680                 bsi->bsi_c_eid->eid_keyval, 0 );
681 #endif /* ! BACKSQL_ARBITRARY_KEY */
682 #endif /* BACKSQL_TRACE */
683
684         rc = SQLExecute( sth );
685         if ( ! BACKSQL_SUCCESS( rc ) ) {
686                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
687                         "error executing attribute query \"%s\"\n",
688                         at->bam_query, 0, 0 );
689                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
690                 SQLFreeStmt( sth, SQL_DROP );
691 #ifdef BACKSQL_COUNTQUERY
692                 if ( append ) {
693                         attr_free( attr );
694                 }
695 #endif /* BACKSQL_COUNTQUERY */
696                 return 1;
697         }
698
699         backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
700 #ifdef BACKSQL_COUNTQUERY
701         j = oldcount;
702 #endif /* BACKSQL_COUNTQUERY */
703         for ( rc = SQLFetch( sth ), k = 0;
704                         BACKSQL_SUCCESS( rc );
705                         rc = SQLFetch( sth ), k++ )
706         {
707                 for ( i = 0; i < (unsigned long)row.ncols; i++ ) {
708
709                         if ( row.value_len[ i ] > 0 ) {
710                                 struct berval           bv;
711                                 int                     retval;
712 #ifdef BACKSQL_TRACE
713                                 AttributeDescription    *ad = NULL;
714                                 const char              *text;
715
716                                 retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
717                                 if ( retval != LDAP_SUCCESS ) {
718                                         Debug( LDAP_DEBUG_ANY,
719                                                 "==>backsql_get_attr_vals(\"%s\"): "
720                                                 "unable to find AttributeDescription %s "
721                                                 "in schema (%d)\n",
722                                                 bsi->bsi_e->e_name.bv_val,
723                                                 row.col_names[ i ].bv_val, retval );
724                                         res = 1;
725                                         goto done;
726                                 }
727
728                                 if ( ad != at->bam_ad ) {
729                                         Debug( LDAP_DEBUG_ANY,
730                                                 "==>backsql_get_attr_vals(\"%s\"): "
731                                                 "column name %s differs from "
732                                                 "AttributeDescription %s\n",
733                                                 bsi->bsi_e->e_name.bv_val,
734                                                 ad->ad_cname.bv_val,
735                                                 at->bam_ad->ad_cname.bv_val );
736                                         res = 1;
737                                         goto done;
738                                 }
739 #endif /* BACKSQL_TRACE */
740
741                                 /*
742                                  * FIXME: what if a binary 
743                                  * is fetched?
744                                  */
745                                 ber_str2bv( row.cols[ i ], 0, 0, &bv );
746
747 #ifdef BACKSQL_PRETTY_VALIDATE
748                                 if ( pretty ) {
749                                         struct berval   pbv;
750
751                                         retval = pretty( at->bam_ad->ad_type->sat_syntax,
752                                                 &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
753                                         bv = pbv;
754
755                                 } else {
756                                         retval = validate( at->bam_ad->ad_type->sat_syntax,
757                                                 &bv );
758                                 }
759
760                                 if ( retval != LDAP_SUCCESS ) {
761                                         char    buf[ SLAP_TEXT_BUFLEN ];
762
763                                         /* FIXME: we're ignoring invalid values,
764                                          * but we're accepting the attributes;
765                                          * should we fail at all? */
766                                         snprintf( buf, sizeof( buf ),
767                                                         "unable to %s value #%lu "
768                                                         "of AttributeDescription %s",
769                                                         pretty ? "prettify" : "validate",
770                                                         k - oldcount,
771                                                         at->bam_ad->ad_cname.bv_val );
772                                         Debug( LDAP_DEBUG_TRACE,
773                                                 "==>backsql_get_attr_vals(\"%s\"): "
774                                                 "%s (%d)\n",
775                                                 bsi->bsi_e->e_name.bv_val, buf, retval );
776                                         continue;
777                                 }
778 #endif /* BACKSQL_PRETTY_VALIDATE */
779
780 #ifndef BACKSQL_COUNTQUERY
781                                 (void)backsql_entry_addattr( bsi->bsi_e, 
782                                                 at->bam_ad, &bv,
783                                                 bsi->bsi_op->o_tmpmemctx );
784
785 #else /* BACKSQL_COUNTQUERY */
786                                 if ( normfunc ) {
787                                         struct berval   nbv;
788
789                                         retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
790                                                 at->bam_ad->ad_type->sat_syntax,
791                                                 at->bam_ad->ad_type->sat_equality,
792                                                 &bv, &nbv,
793                                                 bsi->bsi_op->o_tmpmemctx );
794
795                                         if ( retval != LDAP_SUCCESS ) {
796                                                 char    buf[ SLAP_TEXT_BUFLEN ];
797
798                                                 /* FIXME: we're ignoring invalid values,
799                                                  * but we're accepting the attributes;
800                                                  * should we fail at all? */
801                                                 snprintf( buf, sizeof( buf ),
802                                                         "unable to normalize value #%lu "
803                                                         "of AttributeDescription %s",
804                                                         k - oldcount,
805                                                         at->bam_ad->ad_cname.bv_val );
806                                                 Debug( LDAP_DEBUG_TRACE,
807                                                         "==>backsql_get_attr_vals(\"%s\"): "
808                                                         "%s (%d)\n",
809                                                         bsi->bsi_e->e_name.bv_val, buf, retval );
810
811 #ifdef BACKSQL_PRETTY_VALIDATE
812                                                 if ( pretty ) {
813                                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
814                                                                         bsi->bsi_op->o_tmpmemctx );
815                                                 }
816 #endif /* BACKSQL_PRETTY_VALIDATE */
817
818                                                 continue;
819                                         }
820                                         ber_dupbv( &attr->a_nvals[ j ], &nbv );
821                                         bsi->bsi_op->o_tmpfree( nbv.bv_val,
822                                                         bsi->bsi_op->o_tmpmemctx );
823                                 }
824
825                                 ber_dupbv( &attr->a_vals[ j ], &bv );
826
827                                 assert( j < oldcount + count );
828                                 j++;
829 #endif /* BACKSQL_COUNTQUERY */
830
831 #ifdef BACKSQL_PRETTY_VALIDATE
832                                 if ( pretty ) {
833                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
834                                                         bsi->bsi_op->o_tmpmemctx );
835                                 }
836 #endif /* BACKSQL_PRETTY_VALIDATE */
837
838 #ifdef BACKSQL_TRACE
839                                 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
840                                         (int)row.col_prec[ i ], 0, 0 );
841
842                         } else {
843                                 Debug( LDAP_DEBUG_TRACE, "NULL value "
844                                         "in this row for attribute \"%s\"\n",
845                                         row.col_names[ i ].bv_val, 0, 0 );
846 #endif /* BACKSQL_TRACE */
847                         }
848                 }
849         }
850
851 #ifdef BACKSQL_COUNTQUERY
852         if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
853                 /* don't leave around attributes with no values */
854                 attr_free( attr );
855
856         } else if ( append ) {
857                 Attribute       **ap;
858
859                 for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
860                         /* goto last */ ;
861                 *ap =  attr;
862         }
863 #endif /* BACKSQL_COUNTQUERY */
864
865         SQLFreeStmt( sth, SQL_DROP );
866         Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
867
868         if ( at->bam_next ) {
869                 res = backsql_get_attr_vals( at->bam_next, v_bsi );
870         } else {
871                 res = 1;
872         }
873
874 #ifdef BACKSQL_TRACE
875 done:;
876 #endif /* BACKSQL_TRACE */
877         backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
878
879         return res;
880 }
881
882 int
883 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
884 {
885         Operation               *op = bsi->bsi_op;
886         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
887         int                     i;
888         int                     rc;
889
890         Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
891
892         assert( bsi->bsi_e != NULL );
893
894         memset( bsi->bsi_e, 0, sizeof( Entry ) );
895
896         if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
897                 Entry   *e;
898
899                 e = entry_dup( bi->sql_baseObject );
900                 if ( e == NULL ) {
901                         return LDAP_NO_MEMORY;
902                 }
903                         
904                 *bsi->bsi_e = *e;
905                 free( e );
906                 goto done;
907         }
908
909         ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
910         ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
911
912         bsi->bsi_e->e_attrs = NULL;
913         bsi->bsi_e->e_private = NULL;
914
915         bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
916                         eid->eid_oc_id );
917         bsi->bsi_c_eid = eid;
918
919 #ifndef BACKSQL_ARBITRARY_KEY   
920         /* FIXME: unused */
921         bsi->bsi_e->e_id = eid->eid_id;
922 #endif /* ! BACKSQL_ARBITRARY_KEY */
923  
924         rc = attr_merge_normalize_one( bsi->bsi_e,
925                         slap_schema.si_ad_objectClass,
926                         &bsi->bsi_oc->bom_oc->soc_cname,
927                         bsi->bsi_op->o_tmpmemctx );
928         if ( rc != LDAP_SUCCESS ) {
929                 backsql_entry_clean( op, bsi->bsi_e );
930                 return rc;
931         }
932
933         if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
934         {
935                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
936                         "retrieving all attributes\n", 0, 0, 0 );
937                 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
938                                 bsi, 0, AVL_INORDER );
939
940         } else {
941                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
942                         "custom attribute list\n", 0, 0, 0 );
943                 for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
944                         backsql_at_map_rec      **vat;
945                         AttributeName           *an = &bsi->bsi_attrs[ i ];
946                         int                     j;
947
948                         /* if one of the attributes listed here is
949                          * a subtype of another, it must be ignored,
950                          * because subtypes are already dealt with
951                          * by backsql_supad2at()
952                          */
953                         for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
954                                 /* skip self */
955                                 if ( j == i ) {
956                                         continue;
957                                 }
958
959                                 /* skip subtypes */
960                                 if ( is_at_subtype( an->an_desc->ad_type,
961                                                         bsi->bsi_attrs[ j ].an_desc->ad_type ) )
962                                 {
963                                         goto next;
964                                 }
965                         }
966
967                         rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
968                         if ( rc != 0 || vat == NULL ) {
969                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
970                                                 "attribute \"%s\" is not defined "
971                                                 "for objectlass \"%s\"\n",
972                                                 an->an_name.bv_val, 
973                                                 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
974                                 continue;
975                         }
976
977                         for ( j = 0; vat[j]; j++ ) {
978                                 backsql_get_attr_vals( vat[j], bsi );
979                         }
980
981                         ch_free( vat );
982
983 next:;
984                 }
985         }
986
987         if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
988                 Attribute       *a_entryUUID,
989                                 **ap;
990
991                 a_entryUUID = backsql_operational_entryUUID( bi, eid );
992                 if ( a_entryUUID != NULL ) {
993                         for ( ap = &bsi->bsi_e->e_attrs; 
994                                         *ap; 
995                                         ap = &(*ap)->a_next );
996
997                         *ap = a_entryUUID;
998                 }
999         }
1000
1001         if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
1002                         || an_find( bsi->bsi_attrs, &AllOper )
1003                         || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
1004         {
1005                 ObjectClass     *soc = NULL;
1006
1007                 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
1008                         Attribute       *a;
1009                         const char      *text = NULL;
1010                         char            textbuf[ 1024 ];
1011                         size_t          textlen = sizeof( textbuf );
1012                         struct berval   soc_name,
1013                                         bv[ 2 ],
1014                                         *nvals;
1015                         int             rc = LDAP_SUCCESS;
1016
1017                         a = attr_find( bsi->bsi_e->e_attrs,
1018                                         slap_schema.si_ad_objectClass );
1019                         if ( a != NULL ) {
1020                                 nvals = a->a_nvals;
1021
1022                         } else {
1023                                 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
1024                                 BER_BVZERO( &bv[ 1 ] );
1025                                 nvals = bv;
1026                         }
1027
1028                         rc = structural_class( nvals, &soc_name, &soc, 
1029                                         &text, textbuf, textlen );
1030                         if ( rc != LDAP_SUCCESS ) {
1031                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1032                                         "structural_class() failed %d (%s)\n",
1033                                         bsi->bsi_e->e_name.bv_val,
1034                                         rc, text ? text : "" );
1035                                 backsql_entry_clean( op, bsi->bsi_e );
1036                                 return rc;
1037                         }
1038
1039                         if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
1040                                 if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) {
1041                                         Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1042                                                 "computed structuralObjectClass %s "
1043                                                 "does not match objectClass %s associated "
1044                                                 "to entry\n",
1045                                                 bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
1046                                                 bsi->bsi_oc->bom_oc->soc_cname.bv_val );
1047                                         backsql_entry_clean( op, bsi->bsi_e );
1048                                         return rc;
1049                                 }
1050
1051                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
1052                                         "computed structuralObjectClass %s "
1053                                         "is subclass of 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                         }
1058
1059                 } else {
1060                         soc = bsi->bsi_oc->bom_oc;
1061                 }
1062
1063                 rc = attr_merge_normalize_one( bsi->bsi_e,
1064                                 slap_schema.si_ad_structuralObjectClass,
1065                                 &soc->soc_cname,
1066                                 bsi->bsi_op->o_tmpmemctx );
1067                 if ( rc != LDAP_SUCCESS ) {
1068                         backsql_entry_clean( op, bsi->bsi_e );
1069                         return rc;
1070                 }
1071         }
1072
1073 done:;
1074         Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
1075
1076         return LDAP_SUCCESS;
1077 }
1078