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