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