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