Home | History | Annotate | Line # | Download | only in back-mdb
attr.c revision 1.1.1.1.10.1
      1 /*	$NetBSD: attr.c,v 1.1.1.1.10.1 2017/03/20 06:56:17 pgoyette Exp $	*/
      2 
      3 /* attr.c - backend routines for dealing with attributes */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2000-2016 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 
     19 #include <sys/cdefs.h>
     20 __RCSID("$NetBSD: attr.c,v 1.1.1.1.10.1 2017/03/20 06:56:17 pgoyette Exp $");
     21 
     22 #include "portable.h"
     23 
     24 #include <stdio.h>
     25 
     26 #include <ac/socket.h>
     27 #include <ac/string.h>
     28 
     29 #include "slap.h"
     30 #include "back-mdb.h"
     31 #include "config.h"
     32 #include "lutil.h"
     33 
     34 /* Find the ad, return -1 if not found,
     35  * set point for insertion if ins is non-NULL
     36  */
     37 int
     38 mdb_attr_slot( struct mdb_info *mdb, AttributeDescription *ad, int *ins )
     39 {
     40 	unsigned base = 0, cursor = 0;
     41 	unsigned n = mdb->mi_nattrs;
     42 	int val = 0;
     43 
     44 	while ( 0 < n ) {
     45 		unsigned pivot = n >> 1;
     46 		cursor = base + pivot;
     47 
     48 		val = SLAP_PTRCMP( ad, mdb->mi_attrs[cursor]->ai_desc );
     49 		if ( val < 0 ) {
     50 			n = pivot;
     51 		} else if ( val > 0 ) {
     52 			base = cursor + 1;
     53 			n -= pivot + 1;
     54 		} else {
     55 			return cursor;
     56 		}
     57 	}
     58 	if ( ins ) {
     59 		if ( val > 0 )
     60 			++cursor;
     61 		*ins = cursor;
     62 	}
     63 	return -1;
     64 }
     65 
     66 static int
     67 ainfo_insert( struct mdb_info *mdb, AttrInfo *a )
     68 {
     69 	int x;
     70 	int i = mdb_attr_slot( mdb, a->ai_desc, &x );
     71 
     72 	/* Is it a dup? */
     73 	if ( i >= 0 )
     74 		return -1;
     75 
     76 	mdb->mi_attrs = ch_realloc( mdb->mi_attrs, ( mdb->mi_nattrs+1 ) *
     77 		sizeof( AttrInfo * ));
     78 	if ( x < mdb->mi_nattrs )
     79 		AC_MEMCPY( &mdb->mi_attrs[x+1], &mdb->mi_attrs[x],
     80 			( mdb->mi_nattrs - x ) * sizeof( AttrInfo *));
     81 	mdb->mi_attrs[x] = a;
     82 	mdb->mi_nattrs++;
     83 	return 0;
     84 }
     85 
     86 AttrInfo *
     87 mdb_attr_mask(
     88 	struct mdb_info	*mdb,
     89 	AttributeDescription *desc )
     90 {
     91 	int i = mdb_attr_slot( mdb, desc, NULL );
     92 	return i < 0 ? NULL : mdb->mi_attrs[i];
     93 }
     94 
     95 /* Open all un-opened index DB handles */
     96 int
     97 mdb_attr_dbs_open(
     98 	BackendDB *be, MDB_txn *tx0, ConfigReply *cr )
     99 {
    100 	struct mdb_info *mdb = (struct mdb_info *) be->be_private;
    101 	MDB_txn *txn;
    102 	MDB_dbi *dbis = NULL;
    103 	int i, flags;
    104 	int rc;
    105 
    106 	txn = tx0;
    107 	if ( txn == NULL ) {
    108 		rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &txn );
    109 		if ( rc ) {
    110 			snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
    111 				"txn_begin failed: %s (%d).",
    112 				be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
    113 			Debug( LDAP_DEBUG_ANY,
    114 				LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
    115 				cr->msg, 0, 0 );
    116 			return rc;
    117 		}
    118 		dbis = ch_calloc( 1, mdb->mi_nattrs * sizeof(MDB_dbi) );
    119 	} else {
    120 		rc = 0;
    121 	}
    122 
    123 	flags = MDB_DUPSORT|MDB_DUPFIXED|MDB_INTEGERDUP;
    124 	if ( !(slapMode & SLAP_TOOL_READONLY) )
    125 		flags |= MDB_CREATE;
    126 
    127 	for ( i=0; i<mdb->mi_nattrs; i++ ) {
    128 		if ( mdb->mi_attrs[i]->ai_dbi )	/* already open */
    129 			continue;
    130 		rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
    131 			flags, &mdb->mi_attrs[i]->ai_dbi );
    132 		if ( rc ) {
    133 			snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
    134 				"mdb_dbi_open(%s) failed: %s (%d).",
    135 				be->be_suffix[0].bv_val,
    136 				mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
    137 				mdb_strerror(rc), rc );
    138 			Debug( LDAP_DEBUG_ANY,
    139 				LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
    140 				cr->msg, 0, 0 );
    141 			break;
    142 		}
    143 		/* Remember newly opened DBI handles */
    144 		if ( dbis )
    145 			dbis[i] = mdb->mi_attrs[i]->ai_dbi;
    146 	}
    147 
    148 	/* Only commit if this is our txn */
    149 	if ( tx0 == NULL ) {
    150 		if ( !rc ) {
    151 			rc = mdb_txn_commit( txn );
    152 			if ( rc ) {
    153 				snprintf( cr->msg, sizeof(cr->msg), "database \"%s\": "
    154 					"txn_commit failed: %s (%d).",
    155 					be->be_suffix[0].bv_val, mdb_strerror(rc), rc );
    156 				Debug( LDAP_DEBUG_ANY,
    157 					LDAP_XSTRING(mdb_attr_dbs) ": %s\n",
    158 					cr->msg, 0, 0 );
    159 			}
    160 		} else {
    161 			mdb_txn_abort( txn );
    162 		}
    163 		/* Something failed, forget anything we just opened */
    164 		if ( rc ) {
    165 			for ( i=0; i<mdb->mi_nattrs; i++ ) {
    166 				if ( dbis[i] ) {
    167 					mdb->mi_attrs[i]->ai_dbi = 0;
    168 					mdb->mi_attrs[i]->ai_indexmask |= MDB_INDEX_DELETING;
    169 				}
    170 			}
    171 			mdb_attr_flush( mdb );
    172 		}
    173 		ch_free( dbis );
    174 	}
    175 
    176 	return rc;
    177 }
    178 
    179 void
    180 mdb_attr_dbs_close(
    181 	struct mdb_info *mdb
    182 )
    183 {
    184 	int i;
    185 	for ( i=0; i<mdb->mi_nattrs; i++ )
    186 		if ( mdb->mi_attrs[i]->ai_dbi ) {
    187 			mdb_dbi_close( mdb->mi_dbenv, mdb->mi_attrs[i]->ai_dbi );
    188 			mdb->mi_attrs[i]->ai_dbi = 0;
    189 		}
    190 }
    191 
    192 int
    193 mdb_attr_index_config(
    194 	struct mdb_info	*mdb,
    195 	const char		*fname,
    196 	int			lineno,
    197 	int			argc,
    198 	char		**argv,
    199 	struct		config_reply_s *c_reply)
    200 {
    201 	int rc = 0;
    202 	int	i;
    203 	slap_mask_t mask;
    204 	char **attrs;
    205 	char **indexes = NULL;
    206 
    207 	attrs = ldap_str2charray( argv[0], "," );
    208 
    209 	if( attrs == NULL ) {
    210 		fprintf( stderr, "%s: line %d: "
    211 			"no attributes specified: %s\n",
    212 			fname, lineno, argv[0] );
    213 		return LDAP_PARAM_ERROR;
    214 	}
    215 
    216 	if ( argc > 1 ) {
    217 		indexes = ldap_str2charray( argv[1], "," );
    218 
    219 		if( indexes == NULL ) {
    220 			fprintf( stderr, "%s: line %d: "
    221 				"no indexes specified: %s\n",
    222 				fname, lineno, argv[1] );
    223 			rc = LDAP_PARAM_ERROR;
    224 			goto done;
    225 		}
    226 	}
    227 
    228 	if( indexes == NULL ) {
    229 		mask = mdb->mi_defaultmask;
    230 
    231 	} else {
    232 		mask = 0;
    233 
    234 		for ( i = 0; indexes[i] != NULL; i++ ) {
    235 			slap_mask_t index;
    236 			rc = slap_str2index( indexes[i], &index );
    237 
    238 			if( rc != LDAP_SUCCESS ) {
    239 				if ( c_reply )
    240 				{
    241 					snprintf(c_reply->msg, sizeof(c_reply->msg),
    242 						"index type \"%s\" undefined", indexes[i] );
    243 
    244 					fprintf( stderr, "%s: line %d: %s\n",
    245 						fname, lineno, c_reply->msg );
    246 				}
    247 				rc = LDAP_PARAM_ERROR;
    248 				goto done;
    249 			}
    250 
    251 			mask |= index;
    252 		}
    253 	}
    254 
    255 	if( !mask ) {
    256 		if ( c_reply )
    257 		{
    258 			snprintf(c_reply->msg, sizeof(c_reply->msg),
    259 				"no indexes selected" );
    260 			fprintf( stderr, "%s: line %d: %s\n",
    261 				fname, lineno, c_reply->msg );
    262 		}
    263 		rc = LDAP_PARAM_ERROR;
    264 		goto done;
    265 	}
    266 
    267 	for ( i = 0; attrs[i] != NULL; i++ ) {
    268 		AttrInfo	*a;
    269 		AttributeDescription *ad;
    270 		const char *text;
    271 #ifdef LDAP_COMP_MATCH
    272 		ComponentReference* cr = NULL;
    273 		AttrInfo *a_cr = NULL;
    274 #endif
    275 
    276 		if( strcasecmp( attrs[i], "default" ) == 0 ) {
    277 			mdb->mi_defaultmask |= mask;
    278 			continue;
    279 		}
    280 
    281 #ifdef LDAP_COMP_MATCH
    282 		if ( is_component_reference( attrs[i] ) ) {
    283 			rc = extract_component_reference( attrs[i], &cr );
    284 			if ( rc != LDAP_SUCCESS ) {
    285 				if ( c_reply )
    286 				{
    287 					snprintf(c_reply->msg, sizeof(c_reply->msg),
    288 						"index component reference\"%s\" undefined",
    289 						attrs[i] );
    290 					fprintf( stderr, "%s: line %d: %s\n",
    291 						fname, lineno, c_reply->msg );
    292 				}
    293 				goto done;
    294 			}
    295 			cr->cr_indexmask = mask;
    296 			/*
    297 			 * After extracting a component reference
    298 			 * only the name of a attribute will be remaining
    299 			 */
    300 		} else {
    301 			cr = NULL;
    302 		}
    303 #endif
    304 		ad = NULL;
    305 		rc = slap_str2ad( attrs[i], &ad, &text );
    306 
    307 		if( rc != LDAP_SUCCESS ) {
    308 			if ( c_reply )
    309 			{
    310 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    311 					"index attribute \"%s\" undefined",
    312 					attrs[i] );
    313 
    314 				fprintf( stderr, "%s: line %d: %s\n",
    315 					fname, lineno, c_reply->msg );
    316 			}
    317 			goto done;
    318 		}
    319 
    320 		if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
    321 			if (c_reply) {
    322 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    323 					"index of attribute \"%s\" disallowed", attrs[i] );
    324 				fprintf( stderr, "%s: line %d: %s\n",
    325 					fname, lineno, c_reply->msg );
    326 			}
    327 			rc = LDAP_UNWILLING_TO_PERFORM;
    328 			goto done;
    329 		}
    330 
    331 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
    332 			ad->ad_type->sat_approx
    333 				&& ad->ad_type->sat_approx->smr_indexer
    334 				&& ad->ad_type->sat_approx->smr_filter ) )
    335 		{
    336 			if (c_reply) {
    337 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    338 					"approx index of attribute \"%s\" disallowed", attrs[i] );
    339 				fprintf( stderr, "%s: line %d: %s\n",
    340 					fname, lineno, c_reply->msg );
    341 			}
    342 			rc = LDAP_INAPPROPRIATE_MATCHING;
    343 			goto done;
    344 		}
    345 
    346 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
    347 			ad->ad_type->sat_equality
    348 				&& ad->ad_type->sat_equality->smr_indexer
    349 				&& ad->ad_type->sat_equality->smr_filter ) )
    350 		{
    351 			if (c_reply) {
    352 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    353 					"equality index of attribute \"%s\" disallowed", attrs[i] );
    354 				fprintf( stderr, "%s: line %d: %s\n",
    355 					fname, lineno, c_reply->msg );
    356 			}
    357 			rc = LDAP_INAPPROPRIATE_MATCHING;
    358 			goto done;
    359 		}
    360 
    361 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
    362 			ad->ad_type->sat_substr
    363 				&& ad->ad_type->sat_substr->smr_indexer
    364 				&& ad->ad_type->sat_substr->smr_filter ) )
    365 		{
    366 			if (c_reply) {
    367 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    368 					"substr index of attribute \"%s\" disallowed", attrs[i] );
    369 				fprintf( stderr, "%s: line %d: %s\n",
    370 					fname, lineno, c_reply->msg );
    371 			}
    372 			rc = LDAP_INAPPROPRIATE_MATCHING;
    373 			goto done;
    374 		}
    375 
    376 		Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
    377 			ad->ad_cname.bv_val, mask, 0 );
    378 
    379 		a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
    380 
    381 #ifdef LDAP_COMP_MATCH
    382 		a->ai_cr = NULL;
    383 #endif
    384 		a->ai_cursor = NULL;
    385 		a->ai_flist = NULL;
    386 		a->ai_clist = NULL;
    387 		a->ai_root = NULL;
    388 		a->ai_desc = ad;
    389 		a->ai_dbi = 0;
    390 
    391 		if ( mdb->mi_flags & MDB_IS_OPEN ) {
    392 			a->ai_indexmask = 0;
    393 			a->ai_newmask = mask;
    394 		} else {
    395 			a->ai_indexmask = mask;
    396 			a->ai_newmask = 0;
    397 		}
    398 
    399 #ifdef LDAP_COMP_MATCH
    400 		if ( cr ) {
    401 			a_cr = mdb_attr_mask( mdb, ad );
    402 			if ( a_cr ) {
    403 				/*
    404 				 * AttrInfo is already in AVL
    405 				 * just add the extracted component reference
    406 				 * in the AttrInfo
    407 				 */
    408 				rc = insert_component_reference( cr, &a_cr->ai_cr );
    409 				if ( rc != LDAP_SUCCESS) {
    410 					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
    411 					rc = LDAP_PARAM_ERROR;
    412 					goto done;
    413 				}
    414 				continue;
    415 			} else {
    416 				rc = insert_component_reference( cr, &a->ai_cr );
    417 				if ( rc != LDAP_SUCCESS) {
    418 					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
    419 					rc = LDAP_PARAM_ERROR;
    420 					goto done;
    421 				}
    422 			}
    423 		}
    424 #endif
    425 		rc = ainfo_insert( mdb, a );
    426 		if( rc ) {
    427 			if ( mdb->mi_flags & MDB_IS_OPEN ) {
    428 				AttrInfo *b = mdb_attr_mask( mdb, ad );
    429 				/* If there is already an index defined for this attribute
    430 				 * it must be replaced. Otherwise we end up with multiple
    431 				 * olcIndex values for the same attribute */
    432 				if ( b->ai_indexmask & MDB_INDEX_DELETING ) {
    433 					/* If we were editing this attr, reset it */
    434 					b->ai_indexmask &= ~MDB_INDEX_DELETING;
    435 					/* If this is leftover from a previous add, commit it */
    436 					if ( b->ai_newmask )
    437 						b->ai_indexmask = b->ai_newmask;
    438 					b->ai_newmask = a->ai_newmask;
    439 					ch_free( a );
    440 					rc = 0;
    441 					continue;
    442 				}
    443 			}
    444 			if (c_reply) {
    445 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    446 					"duplicate index definition for attr \"%s\"",
    447 					attrs[i] );
    448 				fprintf( stderr, "%s: line %d: %s\n",
    449 					fname, lineno, c_reply->msg );
    450 			}
    451 
    452 			rc = LDAP_PARAM_ERROR;
    453 			goto done;
    454 		}
    455 	}
    456 
    457 done:
    458 	ldap_charray_free( attrs );
    459 	if ( indexes != NULL ) ldap_charray_free( indexes );
    460 
    461 	return rc;
    462 }
    463 
    464 static int
    465 mdb_attr_index_unparser( void *v1, void *v2 )
    466 {
    467 	AttrInfo *ai = v1;
    468 	BerVarray *bva = v2;
    469 	struct berval bv;
    470 	char *ptr;
    471 
    472 	slap_index2bvlen( ai->ai_indexmask, &bv );
    473 	if ( bv.bv_len ) {
    474 		bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
    475 		ptr = ch_malloc( bv.bv_len+1 );
    476 		bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
    477 		*bv.bv_val++ = ' ';
    478 		slap_index2bv( ai->ai_indexmask, &bv );
    479 		bv.bv_val = ptr;
    480 		ber_bvarray_add( bva, &bv );
    481 	}
    482 	return 0;
    483 }
    484 
    485 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
    486 static AttrInfo aidef = { &addef };
    487 
    488 void
    489 mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
    490 {
    491 	int i;
    492 
    493 	if ( mdb->mi_defaultmask ) {
    494 		aidef.ai_indexmask = mdb->mi_defaultmask;
    495 		mdb_attr_index_unparser( &aidef, bva );
    496 	}
    497 	for ( i=0; i<mdb->mi_nattrs; i++ )
    498 		mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
    499 }
    500 
    501 void
    502 mdb_attr_info_free( AttrInfo *ai )
    503 {
    504 #ifdef LDAP_COMP_MATCH
    505 	free( ai->ai_cr );
    506 #endif
    507 	free( ai );
    508 }
    509 
    510 void
    511 mdb_attr_index_destroy( struct mdb_info *mdb )
    512 {
    513 	int i;
    514 
    515 	for ( i=0; i<mdb->mi_nattrs; i++ )
    516 		mdb_attr_info_free( mdb->mi_attrs[i] );
    517 
    518 	free( mdb->mi_attrs );
    519 }
    520 
    521 void mdb_attr_index_free( struct mdb_info *mdb, AttributeDescription *ad )
    522 {
    523 	int i;
    524 
    525 	i = mdb_attr_slot( mdb, ad, NULL );
    526 	if ( i >= 0 ) {
    527 		mdb_attr_info_free( mdb->mi_attrs[i] );
    528 		mdb->mi_nattrs--;
    529 		for (; i<mdb->mi_nattrs; i++)
    530 			mdb->mi_attrs[i] = mdb->mi_attrs[i+1];
    531 	}
    532 }
    533 
    534 void mdb_attr_flush( struct mdb_info *mdb )
    535 {
    536 	int i;
    537 
    538 	for ( i=0; i<mdb->mi_nattrs; i++ ) {
    539 		if ( mdb->mi_attrs[i]->ai_indexmask & MDB_INDEX_DELETING ) {
    540 			int j;
    541 			mdb_attr_info_free( mdb->mi_attrs[i] );
    542 			mdb->mi_nattrs--;
    543 			for (j=i; j<mdb->mi_nattrs; j++)
    544 				mdb->mi_attrs[j] = mdb->mi_attrs[j+1];
    545 			i--;
    546 		}
    547 	}
    548 }
    549 
    550 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn )
    551 {
    552 	int i, rc;
    553 	MDB_cursor *mc;
    554 	MDB_val key, data;
    555 	struct berval bdata;
    556 	const char *text;
    557 	AttributeDescription *ad;
    558 
    559 	rc = mdb_cursor_open( txn, mdb->mi_ad2id, &mc );
    560 	if ( rc ) {
    561 		Debug( LDAP_DEBUG_ANY,
    562 			"mdb_ad_read: cursor_open failed %s(%d)\n",
    563 			mdb_strerror(rc), rc, 0);
    564 		return rc;
    565 	}
    566 
    567 	/* our array is 1-based, an index of 0 means no data */
    568 	i = mdb->mi_numads+1;
    569 	key.mv_size = sizeof(int);
    570 	key.mv_data = &i;
    571 
    572 	rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
    573 
    574 	while ( rc == MDB_SUCCESS ) {
    575 		bdata.bv_len = data.mv_size;
    576 		bdata.bv_val = data.mv_data;
    577 		ad = NULL;
    578 		rc = slap_bv2ad( &bdata, &ad, &text );
    579 		if ( rc ) {
    580 			rc = slap_bv2undef_ad( &bdata, &mdb->mi_ads[i], &text, 0 );
    581 		} else {
    582 			if ( ad->ad_index >= MDB_MAXADS ) {
    583 				Debug( LDAP_DEBUG_ANY,
    584 					"mdb_adb_read: too many AttributeDescriptions in use\n",
    585 					0, 0, 0 );
    586 				return LDAP_OTHER;
    587 			}
    588 			mdb->mi_adxs[ad->ad_index] = i;
    589 			mdb->mi_ads[i] = ad;
    590 		}
    591 		i++;
    592 		rc = mdb_cursor_get( mc, &key, &data, MDB_NEXT );
    593 	}
    594 	mdb->mi_numads = i-1;
    595 
    596 done:
    597 	if ( rc == MDB_NOTFOUND )
    598 		rc = 0;
    599 
    600 	mdb_cursor_close( mc );
    601 
    602 	return rc;
    603 }
    604 
    605 int mdb_ad_get( struct mdb_info *mdb, MDB_txn *txn, AttributeDescription *ad )
    606 {
    607 	int i, rc;
    608 	MDB_val key, val;
    609 
    610 	rc = mdb_ad_read( mdb, txn );
    611 	if (rc)
    612 		return rc;
    613 
    614 	if ( mdb->mi_adxs[ad->ad_index] )
    615 		return 0;
    616 
    617 	i = mdb->mi_numads+1;
    618 	key.mv_size = sizeof(int);
    619 	key.mv_data = &i;
    620 	val.mv_size = ad->ad_cname.bv_len;
    621 	val.mv_data = ad->ad_cname.bv_val;
    622 
    623 	rc = mdb_put( txn, mdb->mi_ad2id, &key, &val, 0 );
    624 	if ( rc == MDB_SUCCESS ) {
    625 		mdb->mi_adxs[ad->ad_index] = i;
    626 		mdb->mi_ads[i] = ad;
    627 		mdb->mi_numads = i;
    628 	} else {
    629 		Debug( LDAP_DEBUG_ANY,
    630 			"mdb_ad_get: mdb_put failed %s(%d)\n",
    631 			mdb_strerror(rc), rc, 0);
    632 	}
    633 
    634 	return rc;
    635 }
    636