Home | History | Annotate | Line # | Download | only in back-wt
attr.c revision 1.1.1.2
      1 /*	$NetBSD: attr.c,v 1.1.1.2 2025/09/05 21:09:50 christos Exp $	*/
      2 
      3 /* OpenLDAP WiredTiger backend */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2002-2024 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 /* ACKNOWLEDGEMENTS:
     19  * This work was developed by HAMANO Tsukasa <hamano (at) osstech.co.jp>
     20  * based on back-bdb for inclusion in OpenLDAP Software.
     21  * WiredTiger is a product of MongoDB Inc.
     22  */
     23 
     24 #include "back-wt.h"
     25 #include "slap-config.h"
     26 #include "lutil.h"
     27 
     28 /* Find the ad, return -1 if not found,
     29  * set point for insertion if ins is non-NULL
     30  */
     31 int
     32 wt_attr_slot( struct wt_info *wi, AttributeDescription *ad, int *ins )
     33 {
     34 	unsigned base = 0, cursor = 0;
     35 	unsigned n = wi->wi_nattrs;
     36 	int val = 0;
     37 
     38 	while ( 0 < n ) {
     39 		unsigned pivot = n >> 1;
     40 		cursor = base + pivot;
     41 
     42 		val = SLAP_PTRCMP( ad, wi->wi_attrs[cursor]->ai_desc );
     43 		if ( val < 0 ) {
     44 			n = pivot;
     45 		} else if ( val > 0 ) {
     46 			base = cursor + 1;
     47 			n -= pivot + 1;
     48 		} else {
     49 			return cursor;
     50 		}
     51 	}
     52 	if ( ins ) {
     53 		if ( val > 0 )
     54 			++cursor;
     55 		*ins = cursor;
     56 	}
     57 	return -1;
     58 }
     59 
     60 static int
     61 ainfo_insert( struct wt_info *wi, AttrInfo *a )
     62 {
     63 	int x = INT_MAX;
     64 	int i = wt_attr_slot( wi, a->ai_desc, &x );
     65 
     66 	/* Is it a dup? */
     67 	if ( i >= 0 )
     68 		return -1;
     69 
     70 	wi->wi_attrs = ch_realloc( wi->wi_attrs, ( wi->wi_nattrs+1 ) *
     71 							   sizeof( AttrInfo * ));
     72 	if ( x < wi->wi_nattrs )
     73 		AC_MEMCPY( &wi->wi_attrs[x+1], &wi->wi_attrs[x],
     74 				   ( wi->wi_nattrs - x ) * sizeof( AttrInfo *));
     75 	wi->wi_attrs[x] = a;
     76 	wi->wi_nattrs++;
     77 	return 0;
     78 }
     79 
     80 AttrInfo *
     81 wt_attr_mask(
     82 	struct wt_info	*wi,
     83 	AttributeDescription *desc )
     84 {
     85 	int i = wt_attr_slot( wi, desc, NULL );
     86 	return i < 0 ? NULL : wi->wi_attrs[i];
     87 }
     88 
     89 int
     90 wt_attr_index_config(
     91 	struct wt_info	*wi,
     92 	const char		*fname,
     93 	int			lineno,
     94 	int			argc,
     95 	char		**argv,
     96 	struct		config_reply_s *c_reply)
     97 {
     98 	int rc = 0;
     99 	int	i;
    100 	slap_mask_t mask;
    101 	char **attrs;
    102 	char **indexes = NULL;
    103 
    104 	attrs = ldap_str2charray( argv[0], "," );
    105 
    106 	if( attrs == NULL ) {
    107 		fprintf( stderr, "%s: line %d: "
    108 			"no attributes specified: %s\n",
    109 			fname, lineno, argv[0] );
    110 		return LDAP_PARAM_ERROR;
    111 	}
    112 
    113 	if ( argc > 1 ) {
    114 		indexes = ldap_str2charray( argv[1], "," );
    115 
    116 		if( indexes == NULL ) {
    117 			fprintf( stderr, "%s: line %d: "
    118 				"no indexes specified: %s\n",
    119 				fname, lineno, argv[1] );
    120 			rc = LDAP_PARAM_ERROR;
    121 			goto done;
    122 		}
    123 	}
    124 
    125 	if( indexes == NULL ) {
    126 		mask = wi->wi_defaultmask;
    127 
    128 	} else {
    129 		mask = 0;
    130 
    131 		for ( i = 0; indexes[i] != NULL; i++ ) {
    132 			slap_mask_t index;
    133 
    134 			rc = slap_str2index( indexes[i], &index );
    135 
    136 			if( rc != LDAP_SUCCESS ) {
    137 				if ( c_reply )
    138 				{
    139 					snprintf(c_reply->msg, sizeof(c_reply->msg),
    140 						"index type \"%s\" undefined", indexes[i] );
    141 
    142 					fprintf( stderr, "%s: line %d: %s\n",
    143 						fname, lineno, c_reply->msg );
    144 				}
    145 				rc = LDAP_PARAM_ERROR;
    146 				goto done;
    147 			}
    148 
    149 			mask |= index;
    150 		}
    151 	}
    152 
    153 	if( !mask ) {
    154 		if ( c_reply )
    155 		{
    156 			snprintf(c_reply->msg, sizeof(c_reply->msg),
    157 				"no indexes selected" );
    158 			fprintf( stderr, "%s: line %d: %s\n",
    159 				fname, lineno, c_reply->msg );
    160 		}
    161 		rc = LDAP_PARAM_ERROR;
    162 		goto done;
    163 	}
    164 
    165 	for ( i = 0; attrs[i] != NULL; i++ ) {
    166 		AttrInfo	*a;
    167 		AttributeDescription *ad;
    168 		const char *text;
    169 #ifdef LDAP_COMP_MATCH
    170 		ComponentReference* cr = NULL;
    171 		AttrInfo *a_cr = NULL;
    172 #endif
    173 
    174 		if( strcasecmp( attrs[i], "default" ) == 0 ) {
    175 			wi->wi_defaultmask |= mask;
    176 			continue;
    177 		}
    178 
    179 #ifdef LDAP_COMP_MATCH
    180 		if ( is_component_reference( attrs[i] ) ) {
    181 			rc = extract_component_reference( attrs[i], &cr );
    182 			if ( rc != LDAP_SUCCESS ) {
    183 				if ( c_reply )
    184 				{
    185 					snprintf(c_reply->msg, sizeof(c_reply->msg),
    186 						"index component reference\"%s\" undefined",
    187 						attrs[i] );
    188 					fprintf( stderr, "%s: line %d: %s\n",
    189 						fname, lineno, c_reply->msg );
    190 				}
    191 				goto done;
    192 			}
    193 			cr->cr_indexmask = mask;
    194 			/*
    195 			 * After extracting a component reference
    196 			 * only the name of a attribute will be remaining
    197 			 */
    198 		} else {
    199 			cr = NULL;
    200 		}
    201 #endif
    202 		ad = NULL;
    203 		rc = slap_str2ad( attrs[i], &ad, &text );
    204 
    205 		if( rc != LDAP_SUCCESS ) {
    206 			if ( c_reply )
    207 			{
    208 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    209 					"index attribute \"%s\" undefined",
    210 					attrs[i] );
    211 
    212 				fprintf( stderr, "%s: line %d: %s\n",
    213 					fname, lineno, c_reply->msg );
    214 			}
    215 fail:
    216 #ifdef LDAP_COMP_MATCH
    217 			ch_free( cr );
    218 #endif
    219 			goto done;
    220 		}
    221 
    222 		if( ad == slap_schema.si_ad_entryDN || slap_ad_is_binary( ad ) ) {
    223 			if (c_reply) {
    224 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    225 					"index of attribute \"%s\" disallowed", attrs[i] );
    226 				fprintf( stderr, "%s: line %d: %s\n",
    227 					fname, lineno, c_reply->msg );
    228 			}
    229 			rc = LDAP_UNWILLING_TO_PERFORM;
    230 			goto fail;
    231 		}
    232 
    233 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) && !(
    234 			ad->ad_type->sat_approx
    235 				&& ad->ad_type->sat_approx->smr_indexer
    236 				&& ad->ad_type->sat_approx->smr_filter ) )
    237 		{
    238 			if (c_reply) {
    239 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    240 					"approx index of attribute \"%s\" disallowed", attrs[i] );
    241 				fprintf( stderr, "%s: line %d: %s\n",
    242 					fname, lineno, c_reply->msg );
    243 			}
    244 			rc = LDAP_INAPPROPRIATE_MATCHING;
    245 			goto fail;
    246 		}
    247 
    248 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) && !(
    249 			ad->ad_type->sat_equality
    250 				&& ad->ad_type->sat_equality->smr_indexer
    251 				&& ad->ad_type->sat_equality->smr_filter ) )
    252 		{
    253 			if (c_reply) {
    254 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    255 					"equality index of attribute \"%s\" disallowed", attrs[i] );
    256 				fprintf( stderr, "%s: line %d: %s\n",
    257 					fname, lineno, c_reply->msg );
    258 			}
    259 			rc = LDAP_INAPPROPRIATE_MATCHING;
    260 			goto fail;
    261 		}
    262 
    263 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) && !(
    264 			ad->ad_type->sat_substr
    265 				&& ad->ad_type->sat_substr->smr_indexer
    266 				&& ad->ad_type->sat_substr->smr_filter ) )
    267 		{
    268 			if (c_reply) {
    269 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    270 					"substr index of attribute \"%s\" disallowed", attrs[i] );
    271 				fprintf( stderr, "%s: line %d: %s\n",
    272 					fname, lineno, c_reply->msg );
    273 			}
    274 			rc = LDAP_INAPPROPRIATE_MATCHING;
    275 			goto fail;
    276 		}
    277 
    278 		Debug( LDAP_DEBUG_CONFIG, "index %s 0x%04lx\n",
    279 			ad->ad_cname.bv_val, mask );
    280 
    281 		a = (AttrInfo *) ch_malloc( sizeof(AttrInfo) );
    282 
    283 #ifdef LDAP_COMP_MATCH
    284 		a->ai_cr = NULL;
    285 #endif
    286 		a->ai_desc = ad;
    287 
    288 		if ( wi->wi_flags & WT_IS_OPEN ) {
    289 			a->ai_indexmask = 0;
    290 			a->ai_newmask = mask;
    291 		} else {
    292 			a->ai_indexmask = mask;
    293 			a->ai_newmask = 0;
    294 		}
    295 
    296 #ifdef LDAP_COMP_MATCH
    297 		if ( cr ) {
    298 			a_cr = wt_attr_mask( wi, ad );
    299 			if ( a_cr ) {
    300 				/*
    301 				 * AttrInfo is already in AVL
    302 				 * just add the extracted component reference
    303 				 * in the AttrInfo
    304 				 */
    305 				ch_free( a );
    306 				rc = insert_component_reference( cr, &a_cr->ai_cr );
    307 				if ( rc != LDAP_SUCCESS) {
    308 					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
    309 					rc = LDAP_PARAM_ERROR;
    310 					goto fail;
    311 				}
    312 				continue;
    313 			} else {
    314 				rc = insert_component_reference( cr, &a->ai_cr );
    315 				if ( rc != LDAP_SUCCESS) {
    316 					fprintf( stderr, " error during inserting component reference in %s ", attrs[i]);
    317 					rc = LDAP_PARAM_ERROR;
    318 					ch_free( a );
    319 					goto fail;
    320 				}
    321 			}
    322 		}
    323 #endif
    324 		rc = ainfo_insert( wi, a );
    325 		if( rc ) {
    326 			if ( wi->wi_flags & WT_IS_OPEN ) {
    327 				AttrInfo *b = wt_attr_mask( wi, ad );
    328 				/* If there is already an index defined for this attribute
    329 				 * it must be replaced. Otherwise we end up with multiple
    330 				 * olcIndex values for the same attribute */
    331 				if ( b->ai_indexmask & WT_INDEX_DELETING ) {
    332 					/* If we were editing this attr, reset it */
    333 					b->ai_indexmask &= ~WT_INDEX_DELETING;
    334 					/* If this is leftover from a previous add, commit it */
    335 					if ( b->ai_newmask )
    336 						b->ai_indexmask = b->ai_newmask;
    337 					b->ai_newmask = a->ai_newmask;
    338 					ch_free( a );
    339 					rc = 0;
    340 					continue;
    341 				}
    342 			}
    343 			if (c_reply) {
    344 				snprintf(c_reply->msg, sizeof(c_reply->msg),
    345 					"duplicate index definition for attr \"%s\"",
    346 					attrs[i] );
    347 				fprintf( stderr, "%s: line %d: %s\n",
    348 					fname, lineno, c_reply->msg );
    349 			}
    350 
    351 			rc = LDAP_PARAM_ERROR;
    352 			goto done;
    353 		}
    354 	}
    355 
    356 done:
    357 	ldap_charray_free( attrs );
    358 	if ( indexes != NULL ) ldap_charray_free( indexes );
    359 
    360 	return rc;
    361 }
    362 
    363 static int
    364 wt_attr_index_unparser( void *v1, void *v2 )
    365 {
    366 	AttrInfo *ai = v1;
    367 	BerVarray *bva = v2;
    368 	struct berval bv;
    369 	char *ptr;
    370 
    371 	slap_index2bvlen( ai->ai_indexmask, &bv );
    372 	if ( bv.bv_len ) {
    373 		bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
    374 		ptr = ch_malloc( bv.bv_len+1 );
    375 		bv.bv_val = lutil_strcopy(ptr,
    376 								  (const char*)ai->ai_desc->ad_cname.bv_val );
    377 		*bv.bv_val++ = ' ';
    378 		slap_index2bv( ai->ai_indexmask, &bv );
    379 		bv.bv_val = ptr;
    380 		ber_bvarray_add( bva, &bv );
    381 	}
    382 	return 0;
    383 }
    384 
    385 static AttributeDescription addef = { NULL, NULL, BER_BVC("default") };
    386 static AttrInfo aidef = { &addef };
    387 
    388 void
    389 wt_attr_index_unparse( struct wt_info *wi, BerVarray *bva )
    390 {
    391 	int i;
    392 
    393 	if ( wi->wi_defaultmask ) {
    394 		aidef.ai_indexmask = wi->wi_defaultmask;
    395 		wt_attr_index_unparser( &aidef, bva );
    396 	}
    397 	for ( i=0; i<wi->wi_nattrs; i++ )
    398 		wt_attr_index_unparser( wi->wi_attrs[i], bva );
    399 }
    400 
    401 void
    402 wt_attr_info_free( AttrInfo *ai )
    403 {
    404 #ifdef LDAP_COMP_MATCH
    405 	free( ai->ai_cr );
    406 #endif
    407 	free( ai );
    408 }
    409 
    410 void
    411 wt_attr_index_destroy( struct wt_info *wi )
    412 {
    413 	int i;
    414 
    415 	for ( i=0; i<wi->wi_nattrs; i++ )
    416 		wt_attr_info_free( wi->wi_attrs[i] );
    417 
    418 	free( wi->wi_attrs );
    419 }
    420 
    421 /*
    422  * Local variables:
    423  * indent-tabs-mode: t
    424  * tab-width: 4
    425  * c-basic-offset: 4
    426  * End:
    427  */
    428