]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/filterindex.c
Merge remote-tracking branch 'origin/mdb.master'
[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-2013 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 base:
492                         rc = mdb_dn2id( op, rtxn, NULL, &mra->ma_value, &id, NULL, NULL, NULL );
493                         if ( rc == MDB_SUCCESS ) {
494                                 mdb_idl_insert( ids, id );
495                         }
496                         return 0;
497                 } else if ( mra->ma_rule && mra->ma_rule->smr_match ==
498                         dnRelativeMatch && dnIsSuffix( &mra->ma_value,
499                                 op->o_bd->be_nsuffix )) {
500                         int scope;
501                         if ( mra->ma_rule == slap_schema.si_mr_dnSuperiorMatch ) {
502                                 mdb_dn2sups( op, rtxn, &mra->ma_value, ids );
503                                 return 0;
504                         }
505                         if ( mra->ma_rule == slap_schema.si_mr_dnSubtreeMatch )
506                                 scope = LDAP_SCOPE_SUBTREE;
507                         else if ( mra->ma_rule == slap_schema.si_mr_dnOneLevelMatch )
508                                 scope = LDAP_SCOPE_ONELEVEL;
509                         else if ( mra->ma_rule == slap_schema.si_mr_dnSubordinateMatch )
510                                 scope = LDAP_SCOPE_SUBORDINATE;
511                         else
512                                 goto base;      /* scope = LDAP_SCOPE_BASE; */
513 #if 0
514                         if ( scope > LDAP_SCOPE_BASE ) {
515                                 ei = NULL;
516                                 rc = mdb_cache_find_ndn( op, rtxn, &mra->ma_value, &ei );
517                                 if ( ei )
518                                         mdb_cache_entryinfo_unlock( ei );
519                                 if ( rc == LDAP_SUCCESS ) {
520                                         int sc = op->ors_scope;
521                                         op->ors_scope = scope;
522                                         rc = mdb_dn2idl( op, rtxn, &mra->ma_value, ei, ids,
523                                                 stack );
524                                         op->ors_scope = sc;
525                                 }
526                                 return 0;
527                         }
528 #endif
529                 }
530         }
531
532         MDB_IDL_ALL( ids );
533         return 0;
534 }
535
536 static int
537 list_candidates(
538         Operation *op,
539         MDB_txn *rtxn,
540         Filter  *flist,
541         int             ftype,
542         ID *ids,
543         ID *tmp,
544         ID *save )
545 {
546         int rc = 0;
547         Filter  *f;
548
549         Debug( LDAP_DEBUG_FILTER, "=> mdb_list_candidates 0x%x\n", ftype, 0, 0 );
550         for ( f = flist; f != NULL; f = f->f_next ) {
551                 /* ignore precomputed scopes */
552                 if ( f->f_choice == SLAPD_FILTER_COMPUTED &&
553                      f->f_result == LDAP_SUCCESS ) {
554                         continue;
555                 }
556                 MDB_IDL_ZERO( save );
557                 rc = mdb_filter_candidates( op, rtxn, f, save, tmp,
558                         save+MDB_IDL_UM_SIZE );
559
560                 if ( rc != 0 ) {
561                         if ( ftype == LDAP_FILTER_AND ) {
562                                 rc = 0;
563                                 continue;
564                         }
565                         break;
566                 }
567
568                 
569                 if ( ftype == LDAP_FILTER_AND ) {
570                         if ( f == flist ) {
571                                 MDB_IDL_CPY( ids, save );
572                         } else {
573                                 mdb_idl_intersection( ids, save );
574                         }
575                         if( MDB_IDL_IS_ZERO( ids ) )
576                                 break;
577                 } else {
578                         if ( f == flist ) {
579                                 MDB_IDL_CPY( ids, save );
580                         } else {
581                                 mdb_idl_union( ids, save );
582                         }
583                 }
584         }
585
586         if( rc == LDAP_SUCCESS ) {
587                 Debug( LDAP_DEBUG_FILTER,
588                         "<= mdb_list_candidates: id=%ld first=%ld last=%ld\n",
589                         (long) ids[0],
590                         (long) MDB_IDL_FIRST(ids),
591                         (long) MDB_IDL_LAST(ids) );
592
593         } else {
594                 Debug( LDAP_DEBUG_FILTER,
595                         "<= mdb_list_candidates: undefined rc=%d\n",
596                         rc, 0, 0 );
597         }
598
599         return rc;
600 }
601
602 static int
603 presence_candidates(
604         Operation *op,
605         MDB_txn *rtxn,
606         AttributeDescription *desc,
607         ID *ids )
608 {
609         MDB_dbi dbi;
610         int rc;
611         slap_mask_t mask;
612         struct berval prefix = {0, NULL};
613
614         Debug( LDAP_DEBUG_TRACE, "=> mdb_presence_candidates (%s)\n",
615                         desc->ad_cname.bv_val, 0, 0 );
616
617         MDB_IDL_ALL( ids );
618
619         if( desc == slap_schema.si_ad_objectClass ) {
620                 return 0;
621         }
622
623         rc = mdb_index_param( op->o_bd, desc, LDAP_FILTER_PRESENT,
624                 &dbi, &mask, &prefix );
625
626         if( rc == LDAP_INAPPROPRIATE_MATCHING ) {
627                 /* not indexed */
628                 Debug( LDAP_DEBUG_TRACE,
629                         "<= mdb_presence_candidates: (%s) not indexed\n",
630                         desc->ad_cname.bv_val, 0, 0 );
631                 return 0;
632         }
633
634         if( rc != LDAP_SUCCESS ) {
635                 Debug( LDAP_DEBUG_TRACE,
636                         "<= mdb_presence_candidates: (%s) index_param "
637                         "returned=%d\n",
638                         desc->ad_cname.bv_val, rc, 0 );
639                 return 0;
640         }
641
642         if( prefix.bv_val == NULL ) {
643                 Debug( LDAP_DEBUG_TRACE,
644                         "<= mdb_presence_candidates: (%s) no prefix\n",
645                         desc->ad_cname.bv_val, 0, 0 );
646                 return -1;
647         }
648
649         rc = mdb_key_read( op->o_bd, rtxn, dbi, &prefix, ids, NULL, 0 );
650
651         if( rc == MDB_NOTFOUND ) {
652                 MDB_IDL_ZERO( ids );
653                 rc = 0;
654         } else if( rc != LDAP_SUCCESS ) {
655                 Debug( LDAP_DEBUG_TRACE,
656                         "<= mdb_presense_candidates: (%s) "
657                         "key read failed (%d)\n",
658                         desc->ad_cname.bv_val, rc, 0 );
659                 goto done;
660         }
661
662         Debug(LDAP_DEBUG_TRACE,
663                 "<= mdb_presence_candidates: id=%ld first=%ld last=%ld\n",
664                 (long) ids[0],
665                 (long) MDB_IDL_FIRST(ids),
666                 (long) MDB_IDL_LAST(ids) );
667
668 done:
669         return rc;
670 }
671
672 static int
673 equality_candidates(
674         Operation *op,
675         MDB_txn *rtxn,
676         AttributeAssertion *ava,
677         ID *ids,
678         ID *tmp )
679 {
680         MDB_dbi dbi;
681         int i;
682         int rc;
683         slap_mask_t mask;
684         struct berval prefix = {0, NULL};
685         struct berval *keys = NULL;
686         MatchingRule *mr;
687
688         Debug( LDAP_DEBUG_TRACE, "=> mdb_equality_candidates (%s)\n",
689                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
690
691         if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
692                 ID id;
693                 rc = mdb_dn2id( op, rtxn, NULL, &ava->aa_value, &id, NULL, NULL, NULL );
694                 if ( rc == LDAP_SUCCESS ) {
695                         /* exactly one ID can match */
696                         ids[0] = 1;
697                         ids[1] = id;
698                 }
699                 if ( rc == MDB_NOTFOUND ) {
700                         MDB_IDL_ZERO( ids );
701                         rc = 0;
702                 }
703                 return rc;
704         }
705
706         MDB_IDL_ALL( ids );
707
708         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
709                 &dbi, &mask, &prefix );
710
711         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
712                 Debug( LDAP_DEBUG_ANY,
713                         "<= mdb_equality_candidates: (%s) not indexed\n", 
714                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
715                 return 0;
716         }
717
718         if( rc != LDAP_SUCCESS ) {
719                 Debug( LDAP_DEBUG_ANY,
720                         "<= mdb_equality_candidates: (%s) "
721                         "index_param failed (%d)\n",
722                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
723                 return 0;
724         }
725
726         mr = ava->aa_desc->ad_type->sat_equality;
727         if( !mr ) {
728                 return 0;
729         }
730
731         if( !mr->smr_filter ) {
732                 return 0;
733         }
734
735         rc = (mr->smr_filter)(
736                 LDAP_FILTER_EQUALITY,
737                 mask,
738                 ava->aa_desc->ad_type->sat_syntax,
739                 mr,
740                 &prefix,
741                 &ava->aa_value,
742                 &keys, op->o_tmpmemctx );
743
744         if( rc != LDAP_SUCCESS ) {
745                 Debug( LDAP_DEBUG_TRACE,
746                         "<= mdb_equality_candidates: (%s, %s) "
747                         "MR filter failed (%d)\n",
748                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
749                 return 0;
750         }
751
752         if( keys == NULL ) {
753                 Debug( LDAP_DEBUG_TRACE,
754                         "<= mdb_equality_candidates: (%s) no keys\n",
755                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
756                 return 0;
757         }
758
759         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
760                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
761
762                 if( rc == MDB_NOTFOUND ) {
763                         MDB_IDL_ZERO( ids );
764                         rc = 0;
765                         break;
766                 } else if( rc != LDAP_SUCCESS ) {
767                         Debug( LDAP_DEBUG_TRACE,
768                                 "<= mdb_equality_candidates: (%s) "
769                                 "key read failed (%d)\n",
770                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
771                         break;
772                 }
773
774                 if( MDB_IDL_IS_ZERO( tmp ) ) {
775                         Debug( LDAP_DEBUG_TRACE,
776                                 "<= mdb_equality_candidates: (%s) NULL\n", 
777                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
778                         MDB_IDL_ZERO( ids );
779                         break;
780                 }
781
782                 if ( i == 0 ) {
783                         MDB_IDL_CPY( ids, tmp );
784                 } else {
785                         mdb_idl_intersection( ids, tmp );
786                 }
787
788                 if( MDB_IDL_IS_ZERO( ids ) )
789                         break;
790         }
791
792         ber_bvarray_free_x( keys, op->o_tmpmemctx );
793
794         Debug( LDAP_DEBUG_TRACE,
795                 "<= mdb_equality_candidates: id=%ld, first=%ld, last=%ld\n",
796                 (long) ids[0],
797                 (long) MDB_IDL_FIRST(ids),
798                 (long) MDB_IDL_LAST(ids) );
799         return( rc );
800 }
801
802
803 static int
804 approx_candidates(
805         Operation *op,
806         MDB_txn *rtxn,
807         AttributeAssertion *ava,
808         ID *ids,
809         ID *tmp )
810 {
811         MDB_dbi dbi;
812         int i;
813         int rc;
814         slap_mask_t mask;
815         struct berval prefix = {0, NULL};
816         struct berval *keys = NULL;
817         MatchingRule *mr;
818
819         Debug( LDAP_DEBUG_TRACE, "=> mdb_approx_candidates (%s)\n",
820                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
821
822         MDB_IDL_ALL( ids );
823
824         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_APPROX,
825                 &dbi, &mask, &prefix );
826
827         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
828                 Debug( LDAP_DEBUG_ANY,
829                         "<= mdb_approx_candidates: (%s) not indexed\n",
830                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
831                 return 0;
832         }
833
834         if( rc != LDAP_SUCCESS ) {
835                 Debug( LDAP_DEBUG_ANY,
836                         "<= mdb_approx_candidates: (%s) "
837                         "index_param failed (%d)\n",
838                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
839                 return 0;
840         }
841
842         mr = ava->aa_desc->ad_type->sat_approx;
843         if( !mr ) {
844                 /* no approx matching rule, try equality matching rule */
845                 mr = ava->aa_desc->ad_type->sat_equality;
846         }
847
848         if( !mr ) {
849                 return 0;
850         }
851
852         if( !mr->smr_filter ) {
853                 return 0;
854         }
855
856         rc = (mr->smr_filter)(
857                 LDAP_FILTER_APPROX,
858                 mask,
859                 ava->aa_desc->ad_type->sat_syntax,
860                 mr,
861                 &prefix,
862                 &ava->aa_value,
863                 &keys, op->o_tmpmemctx );
864
865         if( rc != LDAP_SUCCESS ) {
866                 Debug( LDAP_DEBUG_TRACE,
867                         "<= mdb_approx_candidates: (%s, %s) "
868                         "MR filter failed (%d)\n",
869                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
870                 return 0;
871         }
872
873         if( keys == NULL ) {
874                 Debug( LDAP_DEBUG_TRACE,
875                         "<= mdb_approx_candidates: (%s) no keys (%s)\n",
876                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, 0 );
877                 return 0;
878         }
879
880         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
881                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
882
883                 if( rc == MDB_NOTFOUND ) {
884                         MDB_IDL_ZERO( ids );
885                         rc = 0;
886                         break;
887                 } else if( rc != LDAP_SUCCESS ) {
888                         Debug( LDAP_DEBUG_TRACE,
889                                 "<= mdb_approx_candidates: (%s) "
890                                 "key read failed (%d)\n",
891                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
892                         break;
893                 }
894
895                 if( MDB_IDL_IS_ZERO( tmp ) ) {
896                         Debug( LDAP_DEBUG_TRACE,
897                                 "<= mdb_approx_candidates: (%s) NULL\n",
898                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
899                         MDB_IDL_ZERO( ids );
900                         break;
901                 }
902
903                 if ( i == 0 ) {
904                         MDB_IDL_CPY( ids, tmp );
905                 } else {
906                         mdb_idl_intersection( ids, tmp );
907                 }
908
909                 if( MDB_IDL_IS_ZERO( ids ) )
910                         break;
911         }
912
913         ber_bvarray_free_x( keys, op->o_tmpmemctx );
914
915         Debug( LDAP_DEBUG_TRACE, "<= mdb_approx_candidates %ld, first=%ld, last=%ld\n",
916                 (long) ids[0],
917                 (long) MDB_IDL_FIRST(ids),
918                 (long) MDB_IDL_LAST(ids) );
919         return( rc );
920 }
921
922 static int
923 substring_candidates(
924         Operation *op,
925         MDB_txn *rtxn,
926         SubstringsAssertion     *sub,
927         ID *ids,
928         ID *tmp )
929 {
930         MDB_dbi dbi;
931         int i;
932         int rc;
933         slap_mask_t mask;
934         struct berval prefix = {0, NULL};
935         struct berval *keys = NULL;
936         MatchingRule *mr;
937
938         Debug( LDAP_DEBUG_TRACE, "=> mdb_substring_candidates (%s)\n",
939                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
940
941         MDB_IDL_ALL( ids );
942
943         rc = mdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS,
944                 &dbi, &mask, &prefix );
945
946         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
947                 Debug( LDAP_DEBUG_ANY,
948                         "<= mdb_substring_candidates: (%s) not indexed\n",
949                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
950                 return 0;
951         }
952
953         if( rc != LDAP_SUCCESS ) {
954                 Debug( LDAP_DEBUG_ANY,
955                         "<= mdb_substring_candidates: (%s) "
956                         "index_param failed (%d)\n",
957                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
958                 return 0;
959         }
960
961         mr = sub->sa_desc->ad_type->sat_substr;
962
963         if( !mr ) {
964                 return 0;
965         }
966
967         if( !mr->smr_filter ) {
968                 return 0;
969         }
970
971         rc = (mr->smr_filter)(
972                 LDAP_FILTER_SUBSTRINGS,
973                 mask,
974                 sub->sa_desc->ad_type->sat_syntax,
975                 mr,
976                 &prefix,
977                 sub,
978                 &keys, op->o_tmpmemctx );
979
980         if( rc != LDAP_SUCCESS ) {
981                 Debug( LDAP_DEBUG_TRACE,
982                         "<= mdb_substring_candidates: (%s) "
983                         "MR filter failed (%d)\n",
984                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
985                 return 0;
986         }
987
988         if( keys == NULL ) {
989                 Debug( LDAP_DEBUG_TRACE,
990                         "<= mdb_substring_candidates: (0x%04lx) no keys (%s)\n",
991                         mask, sub->sa_desc->ad_cname.bv_val, 0 );
992                 return 0;
993         }
994
995         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
996                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
997
998                 if( rc == MDB_NOTFOUND ) {
999                         MDB_IDL_ZERO( ids );
1000                         rc = 0;
1001                         break;
1002                 } else if( rc != LDAP_SUCCESS ) {
1003                         Debug( LDAP_DEBUG_TRACE,
1004                                 "<= mdb_substring_candidates: (%s) "
1005                                 "key read failed (%d)\n",
1006                                 sub->sa_desc->ad_cname.bv_val, rc, 0 );
1007                         break;
1008                 }
1009
1010                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1011                         Debug( LDAP_DEBUG_TRACE,
1012                                 "<= mdb_substring_candidates: (%s) NULL\n",
1013                                 sub->sa_desc->ad_cname.bv_val, 0, 0 );
1014                         MDB_IDL_ZERO( ids );
1015                         break;
1016                 }
1017
1018                 if ( i == 0 ) {
1019                         MDB_IDL_CPY( ids, tmp );
1020                 } else {
1021                         mdb_idl_intersection( ids, tmp );
1022                 }
1023
1024                 if( MDB_IDL_IS_ZERO( ids ) )
1025                         break;
1026         }
1027
1028         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1029
1030         Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: %ld, first=%ld, last=%ld\n",
1031                 (long) ids[0],
1032                 (long) MDB_IDL_FIRST(ids),
1033                 (long) MDB_IDL_LAST(ids) );
1034         return( rc );
1035 }
1036
1037 static int
1038 inequality_candidates(
1039         Operation *op,
1040         MDB_txn *rtxn,
1041         AttributeAssertion *ava,
1042         ID *ids,
1043         ID *tmp,
1044         int gtorlt )
1045 {
1046         MDB_dbi dbi;
1047         int rc;
1048         slap_mask_t mask;
1049         struct berval prefix = {0, NULL};
1050         struct berval *keys = NULL;
1051         MatchingRule *mr;
1052         MDB_cursor *cursor = NULL;
1053
1054         Debug( LDAP_DEBUG_TRACE, "=> mdb_inequality_candidates (%s)\n",
1055                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1056
1057         MDB_IDL_ALL( ids );
1058
1059         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
1060                 &dbi, &mask, &prefix );
1061
1062         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
1063                 Debug( LDAP_DEBUG_ANY,
1064                         "<= mdb_inequality_candidates: (%s) not indexed\n", 
1065                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1066                 return 0;
1067         }
1068
1069         if( rc != LDAP_SUCCESS ) {
1070                 Debug( LDAP_DEBUG_ANY,
1071                         "<= mdb_inequality_candidates: (%s) "
1072                         "index_param failed (%d)\n",
1073                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
1074                 return 0;
1075         }
1076
1077         mr = ava->aa_desc->ad_type->sat_equality;
1078         if( !mr ) {
1079                 return 0;
1080         }
1081
1082         if( !mr->smr_filter ) {
1083                 return 0;
1084         }
1085
1086         rc = (mr->smr_filter)(
1087                 LDAP_FILTER_EQUALITY,
1088                 mask,
1089                 ava->aa_desc->ad_type->sat_syntax,
1090                 mr,
1091                 &prefix,
1092                 &ava->aa_value,
1093                 &keys, op->o_tmpmemctx );
1094
1095         if( rc != LDAP_SUCCESS ) {
1096                 Debug( LDAP_DEBUG_TRACE,
1097                         "<= mdb_inequality_candidates: (%s, %s) "
1098                         "MR filter failed (%d)\n",
1099                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
1100                 return 0;
1101         }
1102
1103         if( keys == NULL ) {
1104                 Debug( LDAP_DEBUG_TRACE,
1105                         "<= mdb_inequality_candidates: (%s) no keys\n",
1106                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1107                 return 0;
1108         }
1109
1110         MDB_IDL_ZERO( ids );
1111         while(1) {
1112                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[0], tmp, &cursor, gtorlt );
1113
1114                 if( rc == MDB_NOTFOUND ) {
1115                         rc = 0;
1116                         break;
1117                 } else if( rc != LDAP_SUCCESS ) {
1118                         Debug( LDAP_DEBUG_TRACE,
1119                                "<= mdb_inequality_candidates: (%s) "
1120                                "key read failed (%d)\n",
1121                                ava->aa_desc->ad_cname.bv_val, rc, 0 );
1122                         break;
1123                 }
1124
1125                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1126                         Debug( LDAP_DEBUG_TRACE,
1127                                "<= mdb_inequality_candidates: (%s) NULL\n", 
1128                                ava->aa_desc->ad_cname.bv_val, 0, 0 );
1129                         break;
1130                 }
1131
1132                 mdb_idl_union( ids, tmp );
1133
1134                 if( op->ors_limit && op->ors_limit->lms_s_unchecked != -1 &&
1135                         MDB_IDL_N( ids ) >= (unsigned) op->ors_limit->lms_s_unchecked ) {
1136                         mdb_cursor_close( cursor );
1137                         break;
1138                 }
1139         }
1140         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1141
1142         Debug( LDAP_DEBUG_TRACE,
1143                 "<= mdb_inequality_candidates: id=%ld, first=%ld, last=%ld\n",
1144                 (long) ids[0],
1145                 (long) MDB_IDL_FIRST(ids),
1146                 (long) MDB_IDL_LAST(ids) );
1147         return( rc );
1148 }