]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/filterindex.c
4f610603618c26709517dd95b28c9412b9578786
[openldap] / servers / slapd / back-mdb / filterindex.c
1 /* filterindex.c - generate the list of candidate entries from a filter */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2011 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
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-mdb.h"
23 #include "idl.h"
24 #ifdef LDAP_COMP_MATCH
25 #include <component.h>
26 #endif
27
28 static int presence_candidates(
29         Operation *op,
30         MDB_txn *rtxn,
31         AttributeDescription *desc,
32         ID *ids );
33
34 static int equality_candidates(
35         Operation *op,
36         MDB_txn *rtxn,
37         AttributeAssertion *ava,
38         ID *ids,
39         ID *tmp );
40 static int inequality_candidates(
41         Operation *op,
42         MDB_txn *rtxn,
43         AttributeAssertion *ava,
44         ID *ids,
45         ID *tmp,
46         int gtorlt );
47 static int approx_candidates(
48         Operation *op,
49         MDB_txn *rtxn,
50         AttributeAssertion *ava,
51         ID *ids,
52         ID *tmp );
53 static int substring_candidates(
54         Operation *op,
55         MDB_txn *rtxn,
56         SubstringsAssertion *sub,
57         ID *ids,
58         ID *tmp );
59
60 static int list_candidates(
61         Operation *op,
62         MDB_txn *rtxn,
63         Filter *flist,
64         int ftype,
65         ID *ids,
66         ID *tmp,
67         ID *stack );
68
69 static int
70 ext_candidates(
71         Operation *op,
72                 MDB_txn *rtxn,
73         MatchingRuleAssertion *mra,
74         ID *ids,
75         ID *tmp,
76         ID *stack);
77
78 #ifdef LDAP_COMP_MATCH
79 static int
80 comp_candidates (
81         Operation *op,
82         MDB_txn *rtxn,
83         MatchingRuleAssertion *mra,
84         ComponentFilter *f,
85         ID *ids,
86         ID *tmp,
87         ID *stack);
88
89 static int
90 ava_comp_candidates (
91                 Operation *op,
92                 MDB_txn *rtxn,
93                 AttributeAssertion *ava,
94                 AttributeAliasing *aa,
95                 ID *ids,
96                 ID *tmp,
97                 ID *stack);
98 #endif
99
100 int
101 mdb_filter_candidates(
102         Operation *op,
103         MDB_txn *rtxn,
104         Filter  *f,
105         ID *ids,
106         ID *tmp,
107         ID *stack )
108 {
109         int rc = 0;
110 #ifdef LDAP_COMP_MATCH
111         AttributeAliasing *aa;
112 #endif
113         Debug( LDAP_DEBUG_FILTER, "=> mdb_filter_candidates\n", 0, 0, 0 );
114
115         if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
116                 MDB_IDL_ZERO( ids );
117                 goto out;
118         }
119
120         switch ( f->f_choice ) {
121         case SLAPD_FILTER_COMPUTED:
122                 switch( f->f_result ) {
123                 case SLAPD_COMPARE_UNDEFINED:
124                 /* This technically is not the same as FALSE, but it
125                  * certainly will produce no matches.
126                  */
127                 /* FALL THRU */
128                 case LDAP_COMPARE_FALSE:
129                         MDB_IDL_ZERO( ids );
130                         break;
131                 case LDAP_COMPARE_TRUE:
132                         MDB_IDL_ALL( ids );
133                         break;
134                 case LDAP_SUCCESS:
135                         /* this is a pre-computed scope, leave it alone */
136                         break;
137                 }
138                 break;
139         case LDAP_FILTER_PRESENT:
140                 Debug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
141                 rc = presence_candidates( op, rtxn, f->f_desc, ids );
142                 break;
143
144         case LDAP_FILTER_EQUALITY:
145                 Debug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
146 #ifdef LDAP_COMP_MATCH
147                 if ( is_aliased_attribute && ( aa = is_aliased_attribute ( f->f_ava->aa_desc ) ) ) {
148                         rc = ava_comp_candidates ( op, rtxn, f->f_ava, aa, ids, tmp, stack );
149                 }
150                 else
151 #endif
152                 {
153                         rc = equality_candidates( op, rtxn, f->f_ava, ids, tmp );
154                 }
155                 break;
156
157         case LDAP_FILTER_APPROX:
158                 Debug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
159                 rc = approx_candidates( op, rtxn, f->f_ava, ids, tmp );
160                 break;
161
162         case LDAP_FILTER_SUBSTRINGS:
163                 Debug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
164                 rc = substring_candidates( op, rtxn, f->f_sub, ids, tmp );
165                 break;
166
167         case LDAP_FILTER_GE:
168                 /* if no GE index, use pres */
169                 Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
170                 if( f->f_ava->aa_desc->ad_type->sat_ordering &&
171                         ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage & SLAP_MR_ORDERED_INDEX ) )
172                         rc = inequality_candidates( op, rtxn, f->f_ava, ids, tmp, LDAP_FILTER_GE );
173                 else
174                         rc = presence_candidates( op, rtxn, f->f_ava->aa_desc, ids );
175                 break;
176
177         case LDAP_FILTER_LE:
178                 /* if no LE index, use pres */
179                 Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
180                 if( f->f_ava->aa_desc->ad_type->sat_ordering &&
181                         ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage & SLAP_MR_ORDERED_INDEX ) )
182                         rc = inequality_candidates( op, rtxn, f->f_ava, ids, tmp, LDAP_FILTER_LE );
183                 else
184                         rc = presence_candidates( op, rtxn, f->f_ava->aa_desc, ids );
185                 break;
186
187         case LDAP_FILTER_NOT:
188                 /* no indexing to support NOT filters */
189                 Debug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
190                 MDB_IDL_ALL( ids );
191                 break;
192
193         case LDAP_FILTER_AND:
194                 Debug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
195                 rc = list_candidates( op, rtxn, 
196                         f->f_and, LDAP_FILTER_AND, ids, tmp, stack );
197                 break;
198
199         case LDAP_FILTER_OR:
200                 Debug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
201                 rc = list_candidates( op, rtxn,
202                         f->f_or, LDAP_FILTER_OR, ids, tmp, stack );
203                 break;
204         case LDAP_FILTER_EXT:
205                 Debug( LDAP_DEBUG_FILTER, "\tEXT\n", 0, 0, 0 );
206                 rc = ext_candidates( op, rtxn, f->f_mra, ids, tmp, stack );
207                 break;
208         default:
209                 Debug( LDAP_DEBUG_FILTER, "\tUNKNOWN %lu\n",
210                         (unsigned long) f->f_choice, 0, 0 );
211                 /* Must not return NULL, otherwise extended filters break */
212                 MDB_IDL_ALL( ids );
213         }
214
215 out:
216         Debug( LDAP_DEBUG_FILTER,
217                 "<= mdb_filter_candidates: id=%ld first=%ld last=%ld\n",
218                 (long) ids[0],
219                 (long) MDB_IDL_FIRST( ids ),
220                 (long) MDB_IDL_LAST( ids ) );
221
222         return rc;
223 }
224
225 #ifdef LDAP_COMP_MATCH
226 static int
227 comp_list_candidates(
228         Operation *op,
229         MDB_txn *rtxn,
230         MatchingRuleAssertion* mra,
231         ComponentFilter *flist,
232         int     ftype,
233         ID *ids,
234         ID *tmp,
235         ID *save )
236 {
237         int rc = 0;
238         ComponentFilter *f;
239
240         Debug( LDAP_DEBUG_FILTER, "=> comp_list_candidates 0x%x\n", ftype, 0, 0 );
241         for ( f = flist; f != NULL; f = f->cf_next ) {
242                 /* ignore precomputed scopes */
243                 if ( f->cf_choice == SLAPD_FILTER_COMPUTED &&
244                      f->cf_result == LDAP_SUCCESS ) {
245                         continue;
246                 }
247                 MDB_IDL_ZERO( save );
248                 rc = comp_candidates( op, rtxn, mra, f, save, tmp, save+MDB_IDL_UM_SIZE );
249
250                 if ( rc != 0 ) {
251                         if ( ftype == LDAP_COMP_FILTER_AND ) {
252                                 rc = 0;
253                                 continue;
254                         }
255                         break;
256                 }
257                 
258                 if ( ftype == LDAP_COMP_FILTER_AND ) {
259                         if ( f == flist ) {
260                                 MDB_IDL_CPY( ids, save );
261                         } else {
262                                 mdb_idl_intersection( ids, save );
263                         }
264                         if( MDB_IDL_IS_ZERO( ids ) )
265                                 break;
266                 } else {
267                         if ( f == flist ) {
268                                 MDB_IDL_CPY( ids, save );
269                         } else {
270                                 mdb_idl_union( ids, save );
271                         }
272                 }
273         }
274
275         if( rc == LDAP_SUCCESS ) {
276                 Debug( LDAP_DEBUG_FILTER,
277                         "<= comp_list_candidates: id=%ld first=%ld last=%ld\n",
278                         (long) ids[0],
279                         (long) MDB_IDL_FIRST(ids),
280                         (long) MDB_IDL_LAST(ids) );
281
282         } else {
283                 Debug( LDAP_DEBUG_FILTER,
284                         "<= comp_list_candidates: undefined rc=%d\n",
285                         rc, 0, 0 );
286         }
287
288         return rc;
289 }
290
291 static int
292 comp_equality_candidates (
293         Operation *op,
294         MDB_txn *rtxn,
295         MatchingRuleAssertion *mra,
296         ComponentAssertion *ca,
297         ID *ids,
298         ID *tmp,
299         ID *stack)
300 {
301         MDB_dbi   dbi;
302         int i;
303         int rc;
304         slap_mask_t mask;
305         struct berval prefix = {0, NULL};
306         struct berval *keys = NULL;
307         MatchingRule *mr = mra->ma_rule;
308         Syntax *sat_syntax;
309         ComponentReference* cr_list, *cr;
310         AttrInfo *ai;
311
312         MDB_IDL_ALL( ids );
313
314         if ( !ca->ca_comp_ref )
315                 return 0;
316
317         ai = mdb_attr_mask( op->o_bd->be_private, mra->ma_desc );
318         if( ai ) {
319                 cr_list = ai->ai_cr;
320         }
321         else {
322                 return 0;
323         }
324         /* find a component reference to be indexed */
325         sat_syntax = ca->ca_ma_rule->smr_syntax;
326         for ( cr = cr_list ; cr ; cr = cr->cr_next ) {
327                 if ( cr->cr_string.bv_len == ca->ca_comp_ref->cr_string.bv_len &&
328                         strncmp( cr->cr_string.bv_val, ca->ca_comp_ref->cr_string.bv_val,cr->cr_string.bv_len ) == 0 )
329                         break;
330         }
331         
332         if ( !cr )
333                 return 0;
334
335         rc = mdb_index_param( op->o_bd, mra->ma_desc, LDAP_FILTER_EQUALITY,
336                         &dbi, &mask, &prefix );
337
338         if( rc != LDAP_SUCCESS ) {
339                 return 0;
340         }
341
342         if( !mr ) {
343                 return 0;
344         }
345
346         if( !mr->smr_filter ) {
347                 return 0;
348         }
349
350         rc = (ca->ca_ma_rule->smr_filter)(
351                                 LDAP_FILTER_EQUALITY,
352                                 cr->cr_indexmask,
353                                 sat_syntax,
354                                 ca->ca_ma_rule,
355                                 &prefix,
356                                 &ca->ca_ma_value,
357                                 &keys, op->o_tmpmemctx );
358
359         if( rc != LDAP_SUCCESS ) {
360                 return 0;
361         }
362
363         if( keys == NULL ) {
364                 return 0;
365         }
366         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
367                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
368
369                 if( rc == MDB_NOTFOUND ) {
370                         MDB_IDL_ZERO( ids );
371                         rc = 0;
372                         break;
373                 } else if( rc != LDAP_SUCCESS ) {
374                         break;
375                 }
376
377                 if( MDB_IDL_IS_ZERO( tmp ) ) {
378                         MDB_IDL_ZERO( ids );
379                         break;
380                 }
381
382                 if ( i == 0 ) {
383                         MDB_IDL_CPY( ids, tmp );
384                 } else {
385                         mdb_idl_intersection( ids, tmp );
386                 }
387
388                 if( MDB_IDL_IS_ZERO( ids ) )
389                         break;
390         }
391         ber_bvarray_free_x( keys, op->o_tmpmemctx );
392
393         Debug( LDAP_DEBUG_TRACE,
394                         "<= comp_equality_candidates: id=%ld, first=%ld, last=%ld\n",
395                         (long) ids[0],
396                         (long) MDB_IDL_FIRST(ids),
397                         (long) MDB_IDL_LAST(ids) );
398         return( rc );
399 }
400
401 static int
402 ava_comp_candidates (
403         Operation *op,
404         MDB_txn *rtxn,
405         AttributeAssertion *ava,
406         AttributeAliasing *aa,
407         ID *ids,
408         ID *tmp,
409         ID *stack )
410 {
411         MatchingRuleAssertion mra;
412         
413         mra.ma_rule = ava->aa_desc->ad_type->sat_equality;
414         if ( !mra.ma_rule ) {
415                 MDB_IDL_ALL( ids );
416                 return 0;
417         }
418         mra.ma_desc = aa->aa_aliased_ad;
419         mra.ma_rule = ava->aa_desc->ad_type->sat_equality;
420         
421         return comp_candidates ( op, rtxn, &mra, ava->aa_cf, ids, tmp, stack );
422 }
423
424 static int
425 comp_candidates (
426         Operation *op,
427         MDB_txn *rtxn,
428         MatchingRuleAssertion *mra,
429         ComponentFilter *f,
430         ID *ids,
431         ID *tmp,
432         ID *stack)
433 {
434         int     rc;
435
436         if ( !f ) return LDAP_PROTOCOL_ERROR;
437
438         Debug( LDAP_DEBUG_FILTER, "comp_candidates\n", 0, 0, 0 );
439         switch ( f->cf_choice ) {
440         case SLAPD_FILTER_COMPUTED:
441                 rc = f->cf_result;
442                 break;
443         case LDAP_COMP_FILTER_AND:
444                 rc = comp_list_candidates( op, rtxn, mra, f->cf_and, LDAP_COMP_FILTER_AND, ids, tmp, stack );
445                 break;
446         case LDAP_COMP_FILTER_OR:
447                 rc = comp_list_candidates( op, rtxn, mra, f->cf_or, LDAP_COMP_FILTER_OR, ids, tmp, stack );
448                 break;
449         case LDAP_COMP_FILTER_NOT:
450                 /* No component indexing supported for NOT filter */
451                 Debug( LDAP_DEBUG_FILTER, "\tComponent NOT\n", 0, 0, 0 );
452                 MDB_IDL_ALL( ids );
453                 rc = LDAP_PROTOCOL_ERROR;
454                 break;
455         case LDAP_COMP_FILTER_ITEM:
456                 rc = comp_equality_candidates( op, rtxn, mra, f->cf_ca, ids, tmp, stack );
457                 break;
458         default:
459                 MDB_IDL_ALL( ids );
460                 rc = LDAP_PROTOCOL_ERROR;
461         }
462
463         return( rc );
464 }
465 #endif
466
467 static int
468 ext_candidates(
469         Operation *op,
470                 MDB_txn *rtxn,
471         MatchingRuleAssertion *mra,
472         ID *ids,
473         ID *tmp,
474         ID *stack)
475 {
476 #ifdef LDAP_COMP_MATCH
477         /*
478          * Currently Only Component Indexing for componentFilterMatch is supported
479          * Indexing for an extensible filter is not supported yet
480          */
481         if ( mra->ma_cf ) {
482                 return comp_candidates ( op, rtxn, mra, mra->ma_cf, ids, tmp, stack);
483         }
484 #endif
485         if ( mra->ma_desc == slap_schema.si_ad_entryDN ) {
486                 int rc;
487                 ID id;
488
489                 MDB_IDL_ZERO( ids );
490                 if ( mra->ma_rule == slap_schema.si_mr_distinguishedNameMatch ) {
491                         rc = mdb_dn2id( op, rtxn, &mra->ma_value, &id, NULL );
492                         if ( rc == MDB_SUCCESS ) {
493                                 mdb_idl_insert( ids, id );
494                         }
495                         return 0;
496                 } else if ( mra->ma_rule && mra->ma_rule->smr_match ==
497                         dnRelativeMatch && dnIsSuffix( &mra->ma_value,
498                                 op->o_bd->be_nsuffix )) {
499                         int scope;
500                         if ( mra->ma_rule == slap_schema.si_mr_dnSuperiorMatch ) {
501                                 struct berval pdn;
502                                 dnParent( &mra->ma_value, &pdn );
503                                 rc = mdb_dn2id( op, rtxn, &pdn, &id, NULL );
504                                 if ( rc == MDB_SUCCESS ) {
505                                         while ( ei && ei->bei_id ) {
506                                                 mdb_idl_insert( ids, ei->bei_id );
507                                                 ei = ei->bei_parent;
508                                         }
509                                 }
510                                 return 0;
511                         }
512                         if ( mra->ma_rule == slap_schema.si_mr_dnSubtreeMatch )
513                                 scope = LDAP_SCOPE_SUBTREE;
514                         else if ( mra->ma_rule == slap_schema.si_mr_dnOneLevelMatch )
515                                 scope = LDAP_SCOPE_ONELEVEL;
516                         else if ( mra->ma_rule == slap_schema.si_mr_dnSubordinateMatch )
517                                 scope = LDAP_SCOPE_SUBORDINATE;
518                         else
519                                 scope = LDAP_SCOPE_BASE;
520                         if ( scope > LDAP_SCOPE_BASE ) {
521                                 ei = NULL;
522                                 rc = mdb_cache_find_ndn( op, rtxn, &mra->ma_value, &ei );
523                                 if ( ei )
524                                         mdb_cache_entryinfo_unlock( ei );
525                                 if ( rc == LDAP_SUCCESS ) {
526                                         int sc = op->ors_scope;
527                                         op->ors_scope = scope;
528                                         rc = mdb_dn2idl( op, rtxn, &mra->ma_value, ei, ids,
529                                                 stack );
530                                         op->ors_scope = sc;
531                                 }
532                                 return 0;
533                         }
534                 }
535         }
536
537         MDB_IDL_ALL( ids );
538         return 0;
539 }
540
541 static int
542 list_candidates(
543         Operation *op,
544         MDB_txn *rtxn,
545         Filter  *flist,
546         int             ftype,
547         ID *ids,
548         ID *tmp,
549         ID *save )
550 {
551         int rc = 0;
552         Filter  *f;
553
554         Debug( LDAP_DEBUG_FILTER, "=> mdb_list_candidates 0x%x\n", ftype, 0, 0 );
555         for ( f = flist; f != NULL; f = f->f_next ) {
556                 /* ignore precomputed scopes */
557                 if ( f->f_choice == SLAPD_FILTER_COMPUTED &&
558                      f->f_result == LDAP_SUCCESS ) {
559                         continue;
560                 }
561                 MDB_IDL_ZERO( save );
562                 rc = mdb_filter_candidates( op, rtxn, f, save, tmp,
563                         save+MDB_IDL_UM_SIZE );
564
565                 if ( rc != 0 ) {
566                         if ( ftype == LDAP_FILTER_AND ) {
567                                 rc = 0;
568                                 continue;
569                         }
570                         break;
571                 }
572
573                 
574                 if ( ftype == LDAP_FILTER_AND ) {
575                         if ( f == flist ) {
576                                 MDB_IDL_CPY( ids, save );
577                         } else {
578                                 mdb_idl_intersection( ids, save );
579                         }
580                         if( MDB_IDL_IS_ZERO( ids ) )
581                                 break;
582                 } else {
583                         if ( f == flist ) {
584                                 MDB_IDL_CPY( ids, save );
585                         } else {
586                                 mdb_idl_union( ids, save );
587                         }
588                 }
589         }
590
591         if( rc == LDAP_SUCCESS ) {
592                 Debug( LDAP_DEBUG_FILTER,
593                         "<= mdb_list_candidates: id=%ld first=%ld last=%ld\n",
594                         (long) ids[0],
595                         (long) MDB_IDL_FIRST(ids),
596                         (long) MDB_IDL_LAST(ids) );
597
598         } else {
599                 Debug( LDAP_DEBUG_FILTER,
600                         "<= mdb_list_candidates: undefined rc=%d\n",
601                         rc, 0, 0 );
602         }
603
604         return rc;
605 }
606
607 static int
608 presence_candidates(
609         Operation *op,
610         MDB_txn *rtxn,
611         AttributeDescription *desc,
612         ID *ids )
613 {
614         MDB_dbi dbi;
615         int rc;
616         slap_mask_t mask;
617         struct berval prefix = {0, NULL};
618
619         Debug( LDAP_DEBUG_TRACE, "=> mdb_presence_candidates (%s)\n",
620                         desc->ad_cname.bv_val, 0, 0 );
621
622         MDB_IDL_ALL( ids );
623
624         if( desc == slap_schema.si_ad_objectClass ) {
625                 return 0;
626         }
627
628         rc = mdb_index_param( op->o_bd, desc, LDAP_FILTER_PRESENT,
629                 &dbi, &mask, &prefix );
630
631         if( rc == LDAP_INAPPROPRIATE_MATCHING ) {
632                 /* not indexed */
633                 Debug( LDAP_DEBUG_TRACE,
634                         "<= mdb_presence_candidates: (%s) not indexed\n",
635                         desc->ad_cname.bv_val, 0, 0 );
636                 return 0;
637         }
638
639         if( rc != LDAP_SUCCESS ) {
640                 Debug( LDAP_DEBUG_TRACE,
641                         "<= mdb_presence_candidates: (%s) index_param "
642                         "returned=%d\n",
643                         desc->ad_cname.bv_val, rc, 0 );
644                 return 0;
645         }
646
647         if( prefix.bv_val == NULL ) {
648                 Debug( LDAP_DEBUG_TRACE,
649                         "<= mdb_presence_candidates: (%s) no prefix\n",
650                         desc->ad_cname.bv_val, 0, 0 );
651                 return -1;
652         }
653
654         rc = mdb_key_read( op->o_bd, rtxn, dbi, &prefix, ids, NULL, 0 );
655
656         if( rc == MDB_NOTFOUND ) {
657                 MDB_IDL_ZERO( ids );
658                 rc = 0;
659         } else if( rc != LDAP_SUCCESS ) {
660                 Debug( LDAP_DEBUG_TRACE,
661                         "<= mdb_presense_candidates: (%s) "
662                         "key read failed (%d)\n",
663                         desc->ad_cname.bv_val, rc, 0 );
664                 goto done;
665         }
666
667         Debug(LDAP_DEBUG_TRACE,
668                 "<= mdb_presence_candidates: id=%ld first=%ld last=%ld\n",
669                 (long) ids[0],
670                 (long) MDB_IDL_FIRST(ids),
671                 (long) MDB_IDL_LAST(ids) );
672
673 done:
674         return rc;
675 }
676
677 static int
678 equality_candidates(
679         Operation *op,
680         MDB_txn *rtxn,
681         AttributeAssertion *ava,
682         ID *ids,
683         ID *tmp )
684 {
685         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
686         MDB_dbi dbi;
687         int i;
688         int rc;
689         slap_mask_t mask;
690         struct berval prefix = {0, NULL};
691         struct berval *keys = NULL;
692         MatchingRule *mr;
693
694         Debug( LDAP_DEBUG_TRACE, "=> mdb_equality_candidates (%s)\n",
695                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
696
697         if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
698                 ID id;
699                 rc = mdb_dn2id( op, rtxn, &ava->aa_value, &id, NULL );
700                 if ( rc == LDAP_SUCCESS ) {
701                         /* exactly one ID can match */
702                         ids[0] = 1;
703                         ids[1] = id;
704                 }
705                 return rc;
706         }
707
708         MDB_IDL_ALL( ids );
709
710         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
711                 &dbi, &mask, &prefix );
712
713         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
714                 Debug( LDAP_DEBUG_ANY,
715                         "<= mdb_equality_candidates: (%s) not indexed\n", 
716                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
717                 return 0;
718         }
719
720         if( rc != LDAP_SUCCESS ) {
721                 Debug( LDAP_DEBUG_ANY,
722                         "<= mdb_equality_candidates: (%s) "
723                         "index_param failed (%d)\n",
724                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
725                 return 0;
726         }
727
728         mr = ava->aa_desc->ad_type->sat_equality;
729         if( !mr ) {
730                 return 0;
731         }
732
733         if( !mr->smr_filter ) {
734                 return 0;
735         }
736
737         rc = (mr->smr_filter)(
738                 LDAP_FILTER_EQUALITY,
739                 mask,
740                 ava->aa_desc->ad_type->sat_syntax,
741                 mr,
742                 &prefix,
743                 &ava->aa_value,
744                 &keys, op->o_tmpmemctx );
745
746         if( rc != LDAP_SUCCESS ) {
747                 Debug( LDAP_DEBUG_TRACE,
748                         "<= mdb_equality_candidates: (%s, %s) "
749                         "MR filter failed (%d)\n",
750                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
751                 return 0;
752         }
753
754         if( keys == NULL ) {
755                 Debug( LDAP_DEBUG_TRACE,
756                         "<= mdb_equality_candidates: (%s) no keys\n",
757                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
758                 return 0;
759         }
760
761         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
762                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
763
764                 if( rc == MDB_NOTFOUND ) {
765                         MDB_IDL_ZERO( ids );
766                         rc = 0;
767                         break;
768                 } else if( rc != LDAP_SUCCESS ) {
769                         Debug( LDAP_DEBUG_TRACE,
770                                 "<= mdb_equality_candidates: (%s) "
771                                 "key read failed (%d)\n",
772                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
773                         break;
774                 }
775
776                 if( MDB_IDL_IS_ZERO( tmp ) ) {
777                         Debug( LDAP_DEBUG_TRACE,
778                                 "<= mdb_equality_candidates: (%s) NULL\n", 
779                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
780                         MDB_IDL_ZERO( ids );
781                         break;
782                 }
783
784                 if ( i == 0 ) {
785                         MDB_IDL_CPY( ids, tmp );
786                 } else {
787                         mdb_idl_intersection( ids, tmp );
788                 }
789
790                 if( MDB_IDL_IS_ZERO( ids ) )
791                         break;
792         }
793
794         ber_bvarray_free_x( keys, op->o_tmpmemctx );
795
796         Debug( LDAP_DEBUG_TRACE,
797                 "<= mdb_equality_candidates: id=%ld, first=%ld, last=%ld\n",
798                 (long) ids[0],
799                 (long) MDB_IDL_FIRST(ids),
800                 (long) MDB_IDL_LAST(ids) );
801         return( rc );
802 }
803
804
805 static int
806 approx_candidates(
807         Operation *op,
808         MDB_txn *rtxn,
809         AttributeAssertion *ava,
810         ID *ids,
811         ID *tmp )
812 {
813         MDB_dbi dbi;
814         int i;
815         int rc;
816         slap_mask_t mask;
817         struct berval prefix = {0, NULL};
818         struct berval *keys = NULL;
819         MatchingRule *mr;
820
821         Debug( LDAP_DEBUG_TRACE, "=> mdb_approx_candidates (%s)\n",
822                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
823
824         MDB_IDL_ALL( ids );
825
826         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_APPROX,
827                 &dbi, &mask, &prefix );
828
829         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
830                 Debug( LDAP_DEBUG_ANY,
831                         "<= mdb_approx_candidates: (%s) not indexed\n",
832                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
833                 return 0;
834         }
835
836         if( rc != LDAP_SUCCESS ) {
837                 Debug( LDAP_DEBUG_ANY,
838                         "<= mdb_approx_candidates: (%s) "
839                         "index_param failed (%d)\n",
840                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
841                 return 0;
842         }
843
844         mr = ava->aa_desc->ad_type->sat_approx;
845         if( !mr ) {
846                 /* no approx matching rule, try equality matching rule */
847                 mr = ava->aa_desc->ad_type->sat_equality;
848         }
849
850         if( !mr ) {
851                 return 0;
852         }
853
854         if( !mr->smr_filter ) {
855                 return 0;
856         }
857
858         rc = (mr->smr_filter)(
859                 LDAP_FILTER_APPROX,
860                 mask,
861                 ava->aa_desc->ad_type->sat_syntax,
862                 mr,
863                 &prefix,
864                 &ava->aa_value,
865                 &keys, op->o_tmpmemctx );
866
867         if( rc != LDAP_SUCCESS ) {
868                 Debug( LDAP_DEBUG_TRACE,
869                         "<= mdb_approx_candidates: (%s, %s) "
870                         "MR filter failed (%d)\n",
871                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
872                 return 0;
873         }
874
875         if( keys == NULL ) {
876                 Debug( LDAP_DEBUG_TRACE,
877                         "<= mdb_approx_candidates: (%s) no keys (%s)\n",
878                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, 0 );
879                 return 0;
880         }
881
882         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
883                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
884
885                 if( rc == MDB_NOTFOUND ) {
886                         MDB_IDL_ZERO( ids );
887                         rc = 0;
888                         break;
889                 } else if( rc != LDAP_SUCCESS ) {
890                         Debug( LDAP_DEBUG_TRACE,
891                                 "<= mdb_approx_candidates: (%s) "
892                                 "key read failed (%d)\n",
893                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
894                         break;
895                 }
896
897                 if( MDB_IDL_IS_ZERO( tmp ) ) {
898                         Debug( LDAP_DEBUG_TRACE,
899                                 "<= mdb_approx_candidates: (%s) NULL\n",
900                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
901                         MDB_IDL_ZERO( ids );
902                         break;
903                 }
904
905                 if ( i == 0 ) {
906                         MDB_IDL_CPY( ids, tmp );
907                 } else {
908                         mdb_idl_intersection( ids, tmp );
909                 }
910
911                 if( MDB_IDL_IS_ZERO( ids ) )
912                         break;
913         }
914
915         ber_bvarray_free_x( keys, op->o_tmpmemctx );
916
917         Debug( LDAP_DEBUG_TRACE, "<= mdb_approx_candidates %ld, first=%ld, last=%ld\n",
918                 (long) ids[0],
919                 (long) MDB_IDL_FIRST(ids),
920                 (long) MDB_IDL_LAST(ids) );
921         return( rc );
922 }
923
924 static int
925 substring_candidates(
926         Operation *op,
927         MDB_txn *rtxn,
928         SubstringsAssertion     *sub,
929         ID *ids,
930         ID *tmp )
931 {
932         MDB_dbi dbi;
933         int i;
934         int rc;
935         slap_mask_t mask;
936         struct berval prefix = {0, NULL};
937         struct berval *keys = NULL;
938         MatchingRule *mr;
939
940         Debug( LDAP_DEBUG_TRACE, "=> mdb_substring_candidates (%s)\n",
941                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
942
943         MDB_IDL_ALL( ids );
944
945         rc = mdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS,
946                 &dbi, &mask, &prefix );
947
948         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
949                 Debug( LDAP_DEBUG_ANY,
950                         "<= mdb_substring_candidates: (%s) not indexed\n",
951                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
952                 return 0;
953         }
954
955         if( rc != LDAP_SUCCESS ) {
956                 Debug( LDAP_DEBUG_ANY,
957                         "<= mdb_substring_candidates: (%s) "
958                         "index_param failed (%d)\n",
959                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
960                 return 0;
961         }
962
963         mr = sub->sa_desc->ad_type->sat_substr;
964
965         if( !mr ) {
966                 return 0;
967         }
968
969         if( !mr->smr_filter ) {
970                 return 0;
971         }
972
973         rc = (mr->smr_filter)(
974                 LDAP_FILTER_SUBSTRINGS,
975                 mask,
976                 sub->sa_desc->ad_type->sat_syntax,
977                 mr,
978                 &prefix,
979                 sub,
980                 &keys, op->o_tmpmemctx );
981
982         if( rc != LDAP_SUCCESS ) {
983                 Debug( LDAP_DEBUG_TRACE,
984                         "<= mdb_substring_candidates: (%s) "
985                         "MR filter failed (%d)\n",
986                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
987                 return 0;
988         }
989
990         if( keys == NULL ) {
991                 Debug( LDAP_DEBUG_TRACE,
992                         "<= mdb_substring_candidates: (0x%04lx) no keys (%s)\n",
993                         mask, sub->sa_desc->ad_cname.bv_val, 0 );
994                 return 0;
995         }
996
997         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
998                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
999
1000                 if( rc == MDB_NOTFOUND ) {
1001                         MDB_IDL_ZERO( ids );
1002                         rc = 0;
1003                         break;
1004                 } else if( rc != LDAP_SUCCESS ) {
1005                         Debug( LDAP_DEBUG_TRACE,
1006                                 "<= mdb_substring_candidates: (%s) "
1007                                 "key read failed (%d)\n",
1008                                 sub->sa_desc->ad_cname.bv_val, rc, 0 );
1009                         break;
1010                 }
1011
1012                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1013                         Debug( LDAP_DEBUG_TRACE,
1014                                 "<= mdb_substring_candidates: (%s) NULL\n",
1015                                 sub->sa_desc->ad_cname.bv_val, 0, 0 );
1016                         MDB_IDL_ZERO( ids );
1017                         break;
1018                 }
1019
1020                 if ( i == 0 ) {
1021                         MDB_IDL_CPY( ids, tmp );
1022                 } else {
1023                         mdb_idl_intersection( ids, tmp );
1024                 }
1025
1026                 if( MDB_IDL_IS_ZERO( ids ) )
1027                         break;
1028         }
1029
1030         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1031
1032         Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: %ld, first=%ld, last=%ld\n",
1033                 (long) ids[0],
1034                 (long) MDB_IDL_FIRST(ids),
1035                 (long) MDB_IDL_LAST(ids) );
1036         return( rc );
1037 }
1038
1039 static int
1040 inequality_candidates(
1041         Operation *op,
1042         MDB_txn *rtxn,
1043         AttributeAssertion *ava,
1044         ID *ids,
1045         ID *tmp,
1046         int gtorlt )
1047 {
1048         MDB_dbi dbi;
1049         int rc;
1050         slap_mask_t mask;
1051         struct berval prefix = {0, NULL};
1052         struct berval *keys = NULL;
1053         MatchingRule *mr;
1054         MDB_cursor *cursor = NULL;
1055
1056         Debug( LDAP_DEBUG_TRACE, "=> mdb_inequality_candidates (%s)\n",
1057                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1058
1059         MDB_IDL_ALL( ids );
1060
1061         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
1062                 &dbi, &mask, &prefix );
1063
1064         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
1065                 Debug( LDAP_DEBUG_ANY,
1066                         "<= mdb_inequality_candidates: (%s) not indexed\n", 
1067                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1068                 return 0;
1069         }
1070
1071         if( rc != LDAP_SUCCESS ) {
1072                 Debug( LDAP_DEBUG_ANY,
1073                         "<= mdb_inequality_candidates: (%s) "
1074                         "index_param failed (%d)\n",
1075                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
1076                 return 0;
1077         }
1078
1079         mr = ava->aa_desc->ad_type->sat_equality;
1080         if( !mr ) {
1081                 return 0;
1082         }
1083
1084         if( !mr->smr_filter ) {
1085                 return 0;
1086         }
1087
1088         rc = (mr->smr_filter)(
1089                 LDAP_FILTER_EQUALITY,
1090                 mask,
1091                 ava->aa_desc->ad_type->sat_syntax,
1092                 mr,
1093                 &prefix,
1094                 &ava->aa_value,
1095                 &keys, op->o_tmpmemctx );
1096
1097         if( rc != LDAP_SUCCESS ) {
1098                 Debug( LDAP_DEBUG_TRACE,
1099                         "<= mdb_inequality_candidates: (%s, %s) "
1100                         "MR filter failed (%d)\n",
1101                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
1102                 return 0;
1103         }
1104
1105         if( keys == NULL ) {
1106                 Debug( LDAP_DEBUG_TRACE,
1107                         "<= mdb_inequality_candidates: (%s) no keys\n",
1108                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1109                 return 0;
1110         }
1111
1112         MDB_IDL_ZERO( ids );
1113         while(1) {
1114                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[0], tmp, &cursor, gtorlt );
1115
1116                 if( rc == MDB_NOTFOUND ) {
1117                         rc = 0;
1118                         break;
1119                 } else if( rc != LDAP_SUCCESS ) {
1120                         Debug( LDAP_DEBUG_TRACE,
1121                                "<= mdb_inequality_candidates: (%s) "
1122                                "key read failed (%d)\n",
1123                                ava->aa_desc->ad_cname.bv_val, rc, 0 );
1124                         break;
1125                 }
1126
1127                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1128                         Debug( LDAP_DEBUG_TRACE,
1129                                "<= mdb_inequality_candidates: (%s) NULL\n", 
1130                                ava->aa_desc->ad_cname.bv_val, 0, 0 );
1131                         break;
1132                 }
1133
1134                 mdb_idl_union( ids, tmp );
1135
1136                 if( op->ors_limit && op->ors_limit->lms_s_unchecked != -1 &&
1137                         MDB_IDL_N( ids ) >= (unsigned) op->ors_limit->lms_s_unchecked ) {
1138                         mdb_cursor_close( cursor );
1139                         break;
1140                 }
1141         }
1142         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1143
1144         Debug( LDAP_DEBUG_TRACE,
1145                 "<= mdb_inequality_candidates: id=%ld, first=%ld, last=%ld\n",
1146                 (long) ids[0],
1147                 (long) MDB_IDL_FIRST(ids),
1148                 (long) MDB_IDL_LAST(ids) );
1149         return( rc );
1150 }