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