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