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