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