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