attr.c revision 1.3 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