1 /* $NetBSD: attr.c,v 1.2 2021/08/14 16:15:02 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@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
wt_attr_slot(struct wt_info * wi,AttributeDescription * ad,int * ins)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
ainfo_insert(struct wt_info * wi,AttrInfo * a)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 *
wt_attr_mask(struct wt_info * wi,AttributeDescription * desc)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
wt_attr_index_config(struct wt_info * wi,const char * fname,int lineno,int argc,char ** argv,struct config_reply_s * c_reply)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
wt_attr_info_free(AttrInfo * ai)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
wt_attr_index_destroy(struct wt_info * wi)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