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