Home | History | Annotate | Line # | Download | only in back-sql
      1 /*	$NetBSD: entry-id.c,v 1.4 2025/09/05 21:16:31 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1999-2024 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 <sys/cdefs.h>
     27 __RCSID("$NetBSD: entry-id.c,v 1.4 2025/09/05 21:16:31 christos Exp $");
     28 
     29 #include "portable.h"
     30 
     31 #include <stdio.h>
     32 #include <sys/types.h>
     33 #include "ac/string.h"
     34 
     35 #include "lutil.h"
     36 #include "slap.h"
     37 #include "proto-sql.h"
     38 
     39 #ifdef BACKSQL_ARBITRARY_KEY
     40 struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR );
     41 #endif /* BACKSQL_ARBITRARY_KEY */
     42 
     43 backsql_entryID *
     44 backsql_entryID_dup( backsql_entryID *src, void *ctx )
     45 {
     46 	backsql_entryID	*dst;
     47 
     48 	if ( src == NULL ) return NULL;
     49 
     50 	dst = slap_sl_calloc( 1, sizeof( backsql_entryID ), ctx );
     51 	ber_dupbv_x( &dst->eid_ndn, &src->eid_ndn, ctx );
     52 	if ( src->eid_dn.bv_val == src->eid_ndn.bv_val ) {
     53 		dst->eid_dn = dst->eid_ndn;
     54 	} else {
     55 		ber_dupbv_x( &dst->eid_dn, &src->eid_dn, ctx );
     56 	}
     57 
     58 #ifdef BACKSQL_ARBITRARY_KEY
     59 	ber_dupbv_x( &dst->eid_id, &src->eid_id, ctx );
     60 	ber_dupbv_x( &dst->eid_keyval, &src->eid_keyval, ctx );
     61 #else /* ! BACKSQL_ARBITRARY_KEY */
     62 	dst->eid_id = src->eid_id;
     63 	dst->eid_keyval = src->eid_keyval;
     64 #endif /* ! BACKSQL_ARBITRARY_KEY */
     65 
     66 	dst->eid_oc = src->eid_oc;
     67 	dst->eid_oc_id = src->eid_oc_id;
     68 
     69 	return dst;
     70 }
     71 
     72 backsql_entryID *
     73 backsql_free_entryID( backsql_entryID *id, int freeit, void *ctx )
     74 {
     75 	backsql_entryID 	*next;
     76 
     77 	assert( id != NULL );
     78 
     79 	next = id->eid_next;
     80 
     81 	if ( !BER_BVISNULL( &id->eid_ndn ) ) {
     82 		if ( !BER_BVISNULL( &id->eid_dn )
     83 				&& id->eid_dn.bv_val != id->eid_ndn.bv_val )
     84 		{
     85 			slap_sl_free( id->eid_dn.bv_val, ctx );
     86 			BER_BVZERO( &id->eid_dn );
     87 		}
     88 
     89 		slap_sl_free( id->eid_ndn.bv_val, ctx );
     90 		BER_BVZERO( &id->eid_ndn );
     91 	}
     92 
     93 #ifdef BACKSQL_ARBITRARY_KEY
     94 	if ( !BER_BVISNULL( &id->eid_id ) ) {
     95 		slap_sl_free( id->eid_id.bv_val, ctx );
     96 		BER_BVZERO( &id->eid_id );
     97 	}
     98 
     99 	if ( !BER_BVISNULL( &id->eid_keyval ) ) {
    100 		slap_sl_free( id->eid_keyval.bv_val, ctx );
    101 		BER_BVZERO( &id->eid_keyval );
    102 	}
    103 #endif /* BACKSQL_ARBITRARY_KEY */
    104 
    105 	if ( freeit ) {
    106 		slap_sl_free( id, ctx );
    107 	}
    108 
    109 	return next;
    110 }
    111 
    112 /*
    113  * NOTE: the dn must be normalized
    114  */
    115 int
    116 backsql_dn2id(
    117 	Operation		*op,
    118 	SlapReply		*rs,
    119 	SQLHDBC			dbh,
    120 	struct berval		*ndn,
    121 	backsql_entryID		*id,
    122 	int			matched,
    123 	int			muck )
    124 {
    125 	backsql_info		*bi = op->o_bd->be_private;
    126 	SQLHSTMT		sth = SQL_NULL_HSTMT;
    127 	BACKSQL_ROW_NTS		row = { 0 };
    128 	RETCODE 		rc;
    129 	int			res;
    130 	struct berval		realndn = BER_BVNULL;
    131 
    132 	/* TimesTen */
    133 	char			upperdn[ BACKSQL_MAX_DN_LEN + 1 ];
    134 	struct berval		tbbDN;
    135 	int			i, j;
    136 
    137 	/*
    138 	 * NOTE: id can be NULL; in this case, the function
    139 	 * simply checks whether the DN can be successfully
    140 	 * turned into an ID, returning LDAP_SUCCESS for
    141 	 * positive cases, or the most appropriate error
    142 	 */
    143 
    144 	Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n",
    145 			ndn->bv_val, id == NULL ? " (no ID expected)" : "",
    146 			matched ? " matched expected" : "" );
    147 
    148 	if ( id ) {
    149 		/* NOTE: trap inconsistencies */
    150 		assert( BER_BVISNULL( &id->eid_ndn ) );
    151 	}
    152 
    153 	if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
    154 		Debug( LDAP_DEBUG_TRACE,
    155 			"   backsql_dn2id(\"%s\"): DN length=%ld "
    156 			"exceeds max DN length %d:\n",
    157 			ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN );
    158 		return LDAP_OTHER;
    159 	}
    160 
    161 	/* return baseObject if available and matches */
    162 	/* FIXME: if ndn is already mucked, we cannot check this */
    163 	if ( bi->sql_baseObject != NULL &&
    164 			dn_match( ndn, &bi->sql_baseObject->e_nname ) )
    165 	{
    166 		if ( id != NULL ) {
    167 #ifdef BACKSQL_ARBITRARY_KEY
    168 			ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv,
    169 					op->o_tmpmemctx );
    170 			ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv,
    171 					op->o_tmpmemctx );
    172 #else /* ! BACKSQL_ARBITRARY_KEY */
    173 			id->eid_id = BACKSQL_BASEOBJECT_ID;
    174 			id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL;
    175 #endif /* ! BACKSQL_ARBITRARY_KEY */
    176 			id->eid_oc_id = BACKSQL_BASEOBJECT_OC;
    177 
    178 			ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname,
    179 					op->o_tmpmemctx );
    180 			ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name,
    181 					op->o_tmpmemctx );
    182 
    183 			id->eid_next = NULL;
    184 		}
    185 
    186 		return LDAP_SUCCESS;
    187 	}
    188 
    189 	/* begin TimesTen */
    190 	assert( bi->sql_id_query != NULL );
    191 	Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): id_query \"%s\"\n",
    192 			ndn->bv_val, bi->sql_id_query );
    193  	rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 );
    194 	if ( rc != SQL_SUCCESS ) {
    195 		Debug( LDAP_DEBUG_TRACE,
    196 			"   backsql_dn2id(\"%s\"): "
    197 			"error preparing SQL:\n   %s",
    198 			ndn->bv_val, bi->sql_id_query );
    199 		backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
    200 		res = LDAP_OTHER;
    201 		goto done;
    202 	}
    203 
    204 	realndn = *ndn;
    205 	if ( muck ) {
    206 		if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
    207 			Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
    208 				"backsql_api_dn2odbc(\"%s\") failed\n",
    209 				ndn->bv_val, realndn.bv_val );
    210 			res = LDAP_OTHER;
    211 			goto done;
    212 		}
    213 	}
    214 
    215 	if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
    216 		/*
    217 		 * Prepare an upper cased, byte reversed version
    218 		 * that can be searched using indexes
    219 		 */
    220 
    221 		for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--)
    222 		{
    223 			upperdn[ i ] = realndn.bv_val[ j ];
    224 		}
    225 		upperdn[ i ] = '\0';
    226 		ldap_pvt_str2upper( upperdn );
    227 
    228 		Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
    229 				"upperdn=\"%s\"\n",
    230 				ndn->bv_val, upperdn );
    231 		ber_str2bv( upperdn, 0, 0, &tbbDN );
    232 
    233 	} else {
    234 		if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
    235 			AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 );
    236 			ldap_pvt_str2upper( upperdn );
    237 			Debug( LDAP_DEBUG_TRACE,
    238 				"   backsql_dn2id(\"%s\"): "
    239 				"upperdn=\"%s\"\n",
    240 				ndn->bv_val, upperdn );
    241 			ber_str2bv( upperdn, 0, 0, &tbbDN );
    242 
    243 		} else {
    244 			tbbDN = realndn;
    245 		}
    246 	}
    247 
    248 	rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN );
    249 	if ( rc != SQL_SUCCESS) {
    250 		/* end TimesTen */
    251 		Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
    252 			"error binding dn=\"%s\" parameter:\n",
    253 			ndn->bv_val, tbbDN.bv_val );
    254 		backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
    255 		res = LDAP_OTHER;
    256 		goto done;
    257 	}
    258 
    259 	rc = SQLExecute( sth );
    260 	if ( rc != SQL_SUCCESS ) {
    261 		Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
    262 			"error executing query (\"%s\", \"%s\"):\n",
    263 			ndn->bv_val, bi->sql_id_query, tbbDN.bv_val );
    264 		backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
    265 		res = LDAP_OTHER;
    266 		goto done;
    267 	}
    268 
    269 	backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx );
    270 	rc = SQLFetch( sth );
    271 	if ( BACKSQL_SUCCESS( rc ) ) {
    272 #ifdef LDAP_DEBUG
    273 		Debug(LDAP_DEBUG_TRACE,
    274 		      "   backsql_dn2id(\"%s\"): id=%s keyval=%s oc_id=%s dn=%s\n",
    275 		      ndn->bv_val, row.cols[0], row.cols[1], row.cols[2],
    276 		      row.cols[3] );
    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 );
    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 );
    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 );
    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 );
    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 );
    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 );
    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 );
    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 );
    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" );
    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 );
    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 );
    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 );
    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" );
    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 );
    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" );
    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) );
    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 );
    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 					/* FIXME: we're ignoring invalid values,
    790 					 * but we're accepting the attributes;
    791 					 * should we fail at all? */
    792 					Debug(LDAP_DEBUG_TRACE,
    793 					      "==>backsql_get_attr_vals(\"%s\"): " "unable to %s value #%lu " "of AttributeDescription %s (%d)\n",
    794 					      bsi->bsi_e->e_name.bv_val,
    795 					      pretty ? "prettify" : "validate",
    796 					      k - oldcount,
    797 					      at->bam_ad->ad_cname.bv_val,
    798 					      retval );
    799 					continue;
    800 				}
    801 #endif /* BACKSQL_PRETTY_VALIDATE */
    802 
    803 #ifndef BACKSQL_COUNTQUERY
    804 				(void)backsql_entry_addattr( bsi->bsi_e,
    805 						at->bam_true_ad, &bv,
    806 						bsi->bsi_op->o_tmpmemctx );
    807 
    808 #else /* BACKSQL_COUNTQUERY */
    809 				if ( normfunc ) {
    810 					struct berval	nbv;
    811 
    812 					retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
    813 						at->bam_true_ad->ad_type->sat_syntax,
    814 						at->bam_true_ad->ad_type->sat_equality,
    815 						&bv, &nbv,
    816 						bsi->bsi_op->o_tmpmemctx );
    817 
    818 					if ( retval != LDAP_SUCCESS ) {
    819 						/* FIXME: we're ignoring invalid values,
    820 						 * but we're accepting the attributes;
    821 						 * should we fail at all? */
    822 						Debug(LDAP_DEBUG_TRACE,
    823 						      "==>backsql_get_attr_vals(\"%s\"): " "unable to normalize value #%lu " "of AttributeDescription %s (%d)\n",
    824 						      bsi->bsi_e->e_name.bv_val,
    825 						      k - oldcount,
    826 						      at->bam_ad->ad_cname.bv_val,
    827 						      retval );
    828 
    829 #ifdef BACKSQL_PRETTY_VALIDATE
    830 						if ( pretty ) {
    831 							bsi->bsi_op->o_tmpfree( bv.bv_val,
    832 									bsi->bsi_op->o_tmpmemctx );
    833 						}
    834 #endif /* BACKSQL_PRETTY_VALIDATE */
    835 
    836 						continue;
    837 					}
    838 					ber_dupbv( &attr->a_nvals[ j ], &nbv );
    839 					bsi->bsi_op->o_tmpfree( nbv.bv_val,
    840 							bsi->bsi_op->o_tmpmemctx );
    841 				}
    842 
    843 				ber_dupbv( &attr->a_vals[ j ], &bv );
    844 
    845 				assert( j < oldcount + count );
    846 				j++;
    847 #endif /* BACKSQL_COUNTQUERY */
    848 
    849 #ifdef BACKSQL_PRETTY_VALIDATE
    850 				if ( pretty ) {
    851 					bsi->bsi_op->o_tmpfree( bv.bv_val,
    852 							bsi->bsi_op->o_tmpmemctx );
    853 				}
    854 #endif /* BACKSQL_PRETTY_VALIDATE */
    855 
    856 #ifdef BACKSQL_TRACE
    857 				Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
    858 					(int)row.col_prec[ i ] );
    859 
    860 			} else {
    861       				Debug( LDAP_DEBUG_TRACE, "NULL value "
    862 					"in this row for attribute \"%s\"\n",
    863 					row.col_names[ i ].bv_val );
    864 #endif /* BACKSQL_TRACE */
    865 			}
    866 		}
    867 	}
    868 
    869 #ifdef BACKSQL_COUNTQUERY
    870 	if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
    871 		/* don't leave around attributes with no values */
    872 		attr_free( attr );
    873 
    874 	} else if ( append ) {
    875 		Attribute	**ap;
    876 
    877 		for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
    878 			/* goto last */ ;
    879 		*ap =  attr;
    880 	}
    881 #endif /* BACKSQL_COUNTQUERY */
    882 
    883 	SQLFreeStmt( sth, SQL_DROP );
    884 	Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n" );
    885 
    886 	if ( at->bam_next ) {
    887 		res = backsql_get_attr_vals( at->bam_next, v_bsi );
    888 	} else {
    889 		res = 1;
    890 	}
    891 
    892 #ifdef BACKSQL_TRACE
    893 done:;
    894 #endif /* BACKSQL_TRACE */
    895 	backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
    896 
    897 	return res;
    898 }
    899 
    900 int
    901 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
    902 {
    903 	Operation		*op = bsi->bsi_op;
    904 	backsql_info		*bi = (backsql_info *)op->o_bd->be_private;
    905 	int			i;
    906 	int			rc;
    907 
    908 	Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n" );
    909 
    910 	assert( bsi->bsi_e != NULL );
    911 
    912 	memset( bsi->bsi_e, 0, sizeof( Entry ) );
    913 
    914 	if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
    915 		(void)entry_dup2( bsi->bsi_e, bi->sql_baseObject );
    916 		goto done;
    917 	}
    918 
    919 	bsi->bsi_e->e_attrs = NULL;
    920 	bsi->bsi_e->e_private = NULL;
    921 
    922 	if ( eid->eid_oc == NULL ) {
    923 		eid->eid_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
    924 			eid->eid_oc_id );
    925 		if ( eid->eid_oc == NULL ) {
    926 			Debug( LDAP_DEBUG_TRACE,
    927 				"backsql_id2entry(): unable to fetch objectClass with id=" BACKSQL_IDNUMFMT " for entry id=" BACKSQL_IDFMT " dn=\"%s\"\n",
    928 				eid->eid_oc_id, BACKSQL_IDARG(eid->eid_id),
    929 				eid->eid_dn.bv_val );
    930 			return LDAP_OTHER;
    931 		}
    932 	}
    933 	bsi->bsi_oc = eid->eid_oc;
    934 	bsi->bsi_c_eid = eid;
    935 
    936 	ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
    937 	ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
    938 
    939 #ifndef BACKSQL_ARBITRARY_KEY
    940 	/* FIXME: unused */
    941 	bsi->bsi_e->e_id = eid->eid_id;
    942 #endif /* ! BACKSQL_ARBITRARY_KEY */
    943 
    944 	rc = attr_merge_normalize_one( bsi->bsi_e,
    945 			slap_schema.si_ad_objectClass,
    946 			&bsi->bsi_oc->bom_oc->soc_cname,
    947 			bsi->bsi_op->o_tmpmemctx );
    948 	if ( rc != LDAP_SUCCESS ) {
    949 		backsql_entry_clean( op, bsi->bsi_e );
    950 		return rc;
    951 	}
    952 
    953 	if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
    954 	{
    955 		Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
    956 			"retrieving all attributes\n" );
    957 		ldap_avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
    958 				bsi, 0, AVL_INORDER );
    959 
    960 	} else {
    961 		Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
    962 			"custom attribute list\n" );
    963 		for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
    964 			backsql_at_map_rec	**vat;
    965 			AttributeName		*an = &bsi->bsi_attrs[ i ];
    966 			int			j;
    967 
    968 			/* if one of the attributes listed here is
    969 			 * a subtype of another, it must be ignored,
    970 			 * because subtypes are already dealt with
    971 			 * by backsql_supad2at()
    972 			 */
    973 			for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
    974 				/* skip self */
    975 				if ( j == i ) {
    976 					continue;
    977 				}
    978 
    979 				/* skip subtypes */
    980 				if ( is_at_subtype( an->an_desc->ad_type,
    981 							bsi->bsi_attrs[ j ].an_desc->ad_type ) )
    982 				{
    983 					goto next;
    984 				}
    985 			}
    986 
    987 			rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
    988 			if ( rc != 0 || vat == NULL ) {
    989 				Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
    990 						"attribute \"%s\" is not defined "
    991 						"for objectclass \"%s\"\n",
    992 						an->an_name.bv_val,
    993 						BACKSQL_OC_NAME( bsi->bsi_oc ) );
    994 				continue;
    995 			}
    996 
    997 			for ( j = 0; vat[j]; j++ ) {
    998     				backsql_get_attr_vals( vat[j], bsi );
    999 			}
   1000 
   1001 			ch_free( vat );
   1002 
   1003 next:;
   1004 		}
   1005 	}
   1006 
   1007 	if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
   1008 		Attribute	*a_entryUUID,
   1009 				**ap;
   1010 
   1011 		a_entryUUID = backsql_operational_entryUUID( bi, eid );
   1012 		if ( a_entryUUID != NULL ) {
   1013 			for ( ap = &bsi->bsi_e->e_attrs;
   1014 					*ap;
   1015 					ap = &(*ap)->a_next );
   1016 
   1017 			*ap = a_entryUUID;
   1018 		}
   1019 	}
   1020 
   1021 	if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
   1022 			|| an_find( bsi->bsi_attrs, slap_bv_all_operational_attrs )
   1023 			|| an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
   1024 	{
   1025 		ObjectClass	*soc = NULL;
   1026 
   1027 		if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
   1028 			Attribute	*a;
   1029 			const char	*text = NULL;
   1030 			char		textbuf[ 1024 ];
   1031 			size_t		textlen = sizeof( textbuf );
   1032 			struct berval	bv[ 2 ],
   1033 					*nvals;
   1034 			int		rc = LDAP_SUCCESS;
   1035 
   1036 			a = attr_find( bsi->bsi_e->e_attrs,
   1037 					slap_schema.si_ad_objectClass );
   1038 			if ( a != NULL ) {
   1039 				nvals = a->a_nvals;
   1040 
   1041 			} else {
   1042 				bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
   1043 				BER_BVZERO( &bv[ 1 ] );
   1044 				nvals = bv;
   1045 			}
   1046 
   1047 			rc = structural_class( nvals, &soc, NULL,
   1048 					&text, textbuf, textlen, op->o_tmpmemctx );
   1049 			if ( rc != LDAP_SUCCESS ) {
   1050       				Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
   1051 					"structural_class() failed %d (%s)\n",
   1052 					bsi->bsi_e->e_name.bv_val,
   1053 					rc, text ? text : "" );
   1054 				backsql_entry_clean( op, bsi->bsi_e );
   1055 				return rc;
   1056 			}
   1057 
   1058 			if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
   1059 				if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) {
   1060       					Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
   1061 						"computed structuralObjectClass %s "
   1062 						"does not match objectClass %s associated "
   1063 						"to entry\n",
   1064 						bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val,
   1065 						bsi->bsi_oc->bom_oc->soc_cname.bv_val );
   1066 					backsql_entry_clean( op, bsi->bsi_e );
   1067 					return rc;
   1068 				}
   1069 
   1070       				Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
   1071 					"computed structuralObjectClass %s "
   1072 					"is subclass of 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 			}
   1077 
   1078 		} else {
   1079 			soc = bsi->bsi_oc->bom_oc;
   1080 		}
   1081 
   1082 		rc = attr_merge_normalize_one( bsi->bsi_e,
   1083 				slap_schema.si_ad_structuralObjectClass,
   1084 				&soc->soc_cname,
   1085 				bsi->bsi_op->o_tmpmemctx );
   1086 		if ( rc != LDAP_SUCCESS ) {
   1087 			backsql_entry_clean( op, bsi->bsi_e );
   1088 			return rc;
   1089 		}
   1090 	}
   1091 
   1092 done:;
   1093 	Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n" );
   1094 
   1095 	return LDAP_SUCCESS;
   1096 }
   1097 
   1098