xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-wt/index.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: index.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 <sys/cdefs.h>
25 __RCSID("$NetBSD: index.c,v 1.2 2021/08/14 16:15:02 christos Exp $");
26 
27 #include "portable.h"
28 
29 #include <stdio.h>
30 #include "back-wt.h"
31 #include "slap-config.h"
32 
33 static char presence_keyval[] = {0,0};
34 static struct berval presence_key = BER_BVC(presence_keyval);
35 
wt_index_mask(Backend * be,AttributeDescription * desc,struct berval * atname)36 AttrInfo *wt_index_mask(
37 	Backend *be,
38 	AttributeDescription *desc,
39 	struct berval *atname )
40 {
41 	AttributeType *at;
42 	AttrInfo *ai = wt_attr_mask( be->be_private, desc );
43 
44 	if( ai ) {
45 		*atname = desc->ad_cname;
46 		return ai;
47 	}
48 
49 	/* If there is a tagging option, did we ever index the base
50 	 * type? If so, check for mask, otherwise it's not there.
51 	 */
52 	if( slap_ad_is_tagged( desc ) && desc != desc->ad_type->sat_ad ) {
53 		/* has tagging option */
54 		ai = wt_attr_mask( be->be_private, desc->ad_type->sat_ad );
55 
56 		if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOTAGS ) ) {
57 			*atname = desc->ad_type->sat_cname;
58 			return ai;
59 		}
60 	}
61 
62 	/* see if supertype defined mask for its subtypes */
63 	for( at = desc->ad_type; at != NULL ; at = at->sat_sup ) {
64 		/* If no AD, we've never indexed this type */
65 		if ( !at->sat_ad ) continue;
66 
67 		ai = wt_attr_mask( be->be_private, at->sat_ad );
68 
69 		if ( ai && !( ai->ai_indexmask & SLAP_INDEX_NOSUBTYPES ) ) {
70 			*atname = at->sat_cname;
71 			return ai;
72 		}
73 	}
74 
75 	return 0;
76 }
77 
78 /* This function is only called when evaluating search filters.
79  */
wt_index_param(Backend * be,AttributeDescription * desc,int ftype,slap_mask_t * maskp,struct berval * prefixp)80 int wt_index_param(
81 	Backend *be,
82 	AttributeDescription *desc,
83 	int ftype,
84 	slap_mask_t *maskp,
85 	struct berval *prefixp )
86 {
87 	AttrInfo *ai;
88 	int rc;
89 	slap_mask_t mask, type = 0;
90 
91 	ai = wt_index_mask( be, desc, prefixp );
92 
93 	if ( !ai ) {
94 		/* TODO: add monitor */
95 		return LDAP_INAPPROPRIATE_MATCHING;
96 	}
97 	mask = ai->ai_indexmask;
98 
99 	switch( ftype ) {
100 	case LDAP_FILTER_PRESENT:
101 		type = SLAP_INDEX_PRESENT;
102 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
103 			*prefixp = presence_key;
104 			*maskp = mask;
105 			return LDAP_SUCCESS;
106 		}
107 		break;
108 
109 	case LDAP_FILTER_APPROX:
110 		type = SLAP_INDEX_APPROX;
111 		if ( desc->ad_type->sat_approx ) {
112 			if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
113 				*maskp = mask;
114 				return LDAP_SUCCESS;
115 			}
116 			break;
117 		}
118 
119 		/* Use EQUALITY rule and index for approximate match */
120 		/* fall thru */
121 
122 	case LDAP_FILTER_EQUALITY:
123 		type = SLAP_INDEX_EQUALITY;
124 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
125 			*maskp = mask;
126 			return LDAP_SUCCESS;
127 		}
128 		break;
129 
130 	case LDAP_FILTER_SUBSTRINGS:
131 		type = SLAP_INDEX_SUBSTR;
132 		if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
133 			*maskp = mask;
134 			return LDAP_SUCCESS;
135 		}
136 		break;
137 
138 	default:
139 		return LDAP_OTHER;
140 	}
141 
142 	/* TODO: add monitor index */
143 	return LDAP_INAPPROPRIATE_MATCHING;
144 }
145 
indexer(Operation * op,wt_ctx * wc,AttributeDescription * ad,struct berval * atname,BerVarray vals,ID id,int opid,slap_mask_t mask)146 static int indexer(
147 	Operation *op,
148 	wt_ctx *wc,
149 	AttributeDescription *ad,
150 	struct berval *atname,
151 	BerVarray vals,
152 	ID id,
153 	int opid,
154 	slap_mask_t mask )
155 {
156 	int rc, i;
157 	struct berval *keys;
158 	WT_CURSOR *cursor = NULL;
159 	WT_SESSION *session = wc->session;
160 	assert( mask != 0 );
161 
162 	cursor = wt_ctx_index_cursor(wc, atname, 1);
163 	if( !cursor ) {
164 		Debug( LDAP_DEBUG_ANY,
165 			   LDAP_XSTRING(indexer)
166 			   ": open index cursor failed: %s\n",
167 			   atname->bv_val );
168 		goto done;
169 	}
170 
171 	if( IS_SLAP_INDEX( mask, SLAP_INDEX_PRESENT ) ) {
172 		rc = wt_key_change( op->o_bd, cursor, &presence_key, id, opid );
173 		if( rc ) {
174 			goto done;
175 		}
176 	}
177 
178 	if( IS_SLAP_INDEX( mask, SLAP_INDEX_EQUALITY ) ) {
179 		rc = ad->ad_type->sat_equality->smr_indexer(
180 			LDAP_FILTER_EQUALITY,
181 			mask,
182 			ad->ad_type->sat_syntax,
183 			ad->ad_type->sat_equality,
184 			atname, vals, &keys, op->o_tmpmemctx );
185 
186 		if( rc == LDAP_SUCCESS && keys != NULL ) {
187 			for( i=0; keys[i].bv_val != NULL; i++ ) {
188 				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
189 				if( rc ) {
190 					ber_bvarray_free_x( keys, op->o_tmpmemctx );
191 					goto done;
192 				}
193 			}
194 			ber_bvarray_free_x( keys, op->o_tmpmemctx );
195 		}
196 		rc = LDAP_SUCCESS;
197 	}
198 
199 	if( IS_SLAP_INDEX( mask, SLAP_INDEX_APPROX ) ) {
200 		rc = ad->ad_type->sat_approx->smr_indexer(
201 			LDAP_FILTER_APPROX,
202 			mask,
203 			ad->ad_type->sat_syntax,
204 			ad->ad_type->sat_approx,
205 			atname, vals, &keys, op->o_tmpmemctx );
206 
207 		if( rc == LDAP_SUCCESS && keys != NULL ) {
208 			for( i=0; keys[i].bv_val != NULL; i++ ) {
209 				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
210 				if( rc ) {
211 					ber_bvarray_free_x( keys, op->o_tmpmemctx );
212 					goto done;
213 				}
214 			}
215 			ber_bvarray_free_x( keys, op->o_tmpmemctx );
216 		}
217 
218 		rc = LDAP_SUCCESS;
219 	}
220 
221 	if( IS_SLAP_INDEX( mask, SLAP_INDEX_SUBSTR ) ) {
222 		rc = ad->ad_type->sat_substr->smr_indexer(
223 			LDAP_FILTER_SUBSTRINGS,
224 			mask,
225 			ad->ad_type->sat_syntax,
226 			ad->ad_type->sat_substr,
227 			atname, vals, &keys, op->o_tmpmemctx );
228 
229 		if( rc == LDAP_SUCCESS && keys != NULL ) {
230 			for( i=0; keys[i].bv_val != NULL; i++ ) {
231 				rc = wt_key_change( op->o_bd, cursor, &keys[i], id, opid );
232 				if( rc ) {
233 					ber_bvarray_free_x( keys, op->o_tmpmemctx );
234 					goto done;
235 				}
236 			}
237 			ber_bvarray_free_x( keys, op->o_tmpmemctx );
238 		}
239 
240 		rc = LDAP_SUCCESS;
241 	}
242 
243 done:
244 	if(cursor){
245 		cursor->close(cursor);
246 	}
247 	return rc;
248 }
249 
index_at_values(Operation * op,wt_ctx * wc,AttributeDescription * ad,AttributeType * type,struct berval * tags,BerVarray vals,ID id,int opid)250 static int index_at_values(
251 	Operation *op,
252 	wt_ctx *wc,
253 	AttributeDescription *ad,
254 	AttributeType *type,
255 	struct berval *tags,
256 	BerVarray vals,
257 	ID id,
258 	int opid )
259 {
260 	int rc;
261 	slap_mask_t mask = 0;
262 	int ixop = opid;
263 	AttrInfo *ai = NULL;
264 
265 	if ( opid == WT_INDEX_UPDATE_OP )
266 		ixop = SLAP_INDEX_ADD_OP;
267 
268 	if( type->sat_sup ) {
269 		/* recurse */
270 		rc = index_at_values( op, wc, NULL,
271 							  type->sat_sup, tags,
272 							  vals, id, opid );
273 
274 		if( rc ) return rc;
275 	}
276 
277 	/* If this type has no AD, we've never used it before */
278 	if( type->sat_ad ) {
279 		ai = wt_attr_mask( op->o_bd->be_private, type->sat_ad );
280 		if ( ai ) {
281 			#ifdef LDAP_COMP_MATCH
282 			/* component indexing */
283 			if ( ai->ai_cr ) {
284 				ComponentReference *cr;
285 				for( cr = ai->ai_cr ; cr ; cr = cr->cr_next ) {
286 					rc = indexer( op, wc, cr->cr_ad, &type->sat_cname,
287 								  cr->cr_nvals, id, ixop,
288 								  cr->cr_indexmask );
289 				}
290 			}
291 			#endif
292 			ad = type->sat_ad;
293 			/* If we're updating the index, just set the new bits that aren't
294              * already in the old mask.
295              */
296 			if ( opid == WT_INDEX_UPDATE_OP )
297 				mask = ai->ai_newmask & ~ai->ai_indexmask;
298 			else
299 				/* For regular updates, if there is a newmask use it. Otherwise
300 				 * just use the old mask.
301 				 */
302 				mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
303 			if( mask ) {
304 				rc = indexer( op, wc, ad, &type->sat_cname,
305 							  vals, id, ixop, mask );
306 				if( rc ) return rc;
307 			}
308 		}
309 	}
310 
311 	if( tags->bv_len ) {
312 		AttributeDescription *desc;
313 
314 		desc = ad_find_tags( type, tags );
315 		if( desc ) {
316 			ai = wt_attr_mask( op->o_bd->be_private, desc );
317 
318 			if( ai ) {
319 				if ( opid == WT_INDEX_UPDATE_OP )
320 					mask = ai->ai_newmask & ~ai->ai_indexmask;
321 				else
322 					mask = ai->ai_newmask ? ai->ai_newmask : ai->ai_indexmask;
323 				if ( mask ) {
324 					rc = indexer( op, wc, desc, &desc->ad_cname,
325 								  vals, id, ixop, mask );
326 
327 					if( rc ) {
328 						return rc;
329 					}
330 				}
331 			}
332 		}
333 	}
334 
335 	return LDAP_SUCCESS;
336 }
337 
wt_index_values(Operation * op,wt_ctx * wc,AttributeDescription * desc,BerVarray vals,ID id,int opid)338 int wt_index_values(
339 	Operation *op,
340 	wt_ctx *wc,
341 	AttributeDescription *desc,
342 	BerVarray vals,
343 	ID id,
344 	int opid )
345 {
346 	int rc;
347 
348 	/* Never index ID 0 */
349 	if ( id == 0 )
350 		return 0;
351 
352 	rc = index_at_values( op, wc, desc,
353 						  desc->ad_type, &desc->ad_tags,
354 						  vals, id, opid );
355 
356 	return rc;
357 }
358 
359 int
wt_index_entry(Operation * op,wt_ctx * wc,int opid,Entry * e)360 wt_index_entry( Operation *op, wt_ctx *wc, int opid, Entry *e )
361 {
362 	int rc;
363 	Attribute *ap = e->e_attrs;
364 
365 	if ( e->e_id == 0 )
366 		return 0;
367 
368 	Debug( LDAP_DEBUG_TRACE, "=> index_entry_%s( %ld, \"%s\" )\n",
369 		   opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
370 		   (long) e->e_id, e->e_dn ? e->e_dn : "" );
371 
372 	for ( ; ap != NULL; ap = ap->a_next ) {
373 		rc = wt_index_values( op, wc, ap->a_desc,
374 							  ap->a_nvals, e->e_id, opid );
375 		if( rc != LDAP_SUCCESS ) {
376 			Debug( LDAP_DEBUG_TRACE,
377 				   "<= index_entry_%s( %ld, \"%s\" ) failure\n",
378 				   opid == SLAP_INDEX_ADD_OP ? "add" : "del",
379 				   (long) e->e_id, e->e_dn );
380 			return rc;
381 		}
382 	}
383 
384 	Debug( LDAP_DEBUG_TRACE, "<= index_entry_%s( %ld, \"%s\" ) success\n",
385 		   opid == SLAP_INDEX_DELETE_OP ? "del" : "add",
386 		   (long) e->e_id, e->e_dn ? e->e_dn : "" );
387 	return 0;
388 }
389 
390 /*
391  * Local variables:
392  * indent-tabs-mode: t
393  * tab-width: 4
394  * c-basic-offset: 4
395  * End:
396  */
397