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