]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/filterindex.c
e2142e1dfe721d4fc471d39a36244945b8cdd73b
[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                 return rc;
700         }
701
702         MDB_IDL_ALL( ids );
703
704         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
705                 &dbi, &mask, &prefix );
706
707         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
708                 Debug( LDAP_DEBUG_ANY,
709                         "<= mdb_equality_candidates: (%s) not indexed\n", 
710                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
711                 return 0;
712         }
713
714         if( rc != LDAP_SUCCESS ) {
715                 Debug( LDAP_DEBUG_ANY,
716                         "<= mdb_equality_candidates: (%s) "
717                         "index_param failed (%d)\n",
718                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
719                 return 0;
720         }
721
722         mr = ava->aa_desc->ad_type->sat_equality;
723         if( !mr ) {
724                 return 0;
725         }
726
727         if( !mr->smr_filter ) {
728                 return 0;
729         }
730
731         rc = (mr->smr_filter)(
732                 LDAP_FILTER_EQUALITY,
733                 mask,
734                 ava->aa_desc->ad_type->sat_syntax,
735                 mr,
736                 &prefix,
737                 &ava->aa_value,
738                 &keys, op->o_tmpmemctx );
739
740         if( rc != LDAP_SUCCESS ) {
741                 Debug( LDAP_DEBUG_TRACE,
742                         "<= mdb_equality_candidates: (%s, %s) "
743                         "MR filter failed (%d)\n",
744                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
745                 return 0;
746         }
747
748         if( keys == NULL ) {
749                 Debug( LDAP_DEBUG_TRACE,
750                         "<= mdb_equality_candidates: (%s) no keys\n",
751                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
752                 return 0;
753         }
754
755         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
756                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
757
758                 if( rc == MDB_NOTFOUND ) {
759                         MDB_IDL_ZERO( ids );
760                         rc = 0;
761                         break;
762                 } else if( rc != LDAP_SUCCESS ) {
763                         Debug( LDAP_DEBUG_TRACE,
764                                 "<= mdb_equality_candidates: (%s) "
765                                 "key read failed (%d)\n",
766                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
767                         break;
768                 }
769
770                 if( MDB_IDL_IS_ZERO( tmp ) ) {
771                         Debug( LDAP_DEBUG_TRACE,
772                                 "<= mdb_equality_candidates: (%s) NULL\n", 
773                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
774                         MDB_IDL_ZERO( ids );
775                         break;
776                 }
777
778                 if ( i == 0 ) {
779                         MDB_IDL_CPY( ids, tmp );
780                 } else {
781                         mdb_idl_intersection( ids, tmp );
782                 }
783
784                 if( MDB_IDL_IS_ZERO( ids ) )
785                         break;
786         }
787
788         ber_bvarray_free_x( keys, op->o_tmpmemctx );
789
790         Debug( LDAP_DEBUG_TRACE,
791                 "<= mdb_equality_candidates: id=%ld, first=%ld, last=%ld\n",
792                 (long) ids[0],
793                 (long) MDB_IDL_FIRST(ids),
794                 (long) MDB_IDL_LAST(ids) );
795         return( rc );
796 }
797
798
799 static int
800 approx_candidates(
801         Operation *op,
802         MDB_txn *rtxn,
803         AttributeAssertion *ava,
804         ID *ids,
805         ID *tmp )
806 {
807         MDB_dbi dbi;
808         int i;
809         int rc;
810         slap_mask_t mask;
811         struct berval prefix = {0, NULL};
812         struct berval *keys = NULL;
813         MatchingRule *mr;
814
815         Debug( LDAP_DEBUG_TRACE, "=> mdb_approx_candidates (%s)\n",
816                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
817
818         MDB_IDL_ALL( ids );
819
820         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_APPROX,
821                 &dbi, &mask, &prefix );
822
823         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
824                 Debug( LDAP_DEBUG_ANY,
825                         "<= mdb_approx_candidates: (%s) not indexed\n",
826                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
827                 return 0;
828         }
829
830         if( rc != LDAP_SUCCESS ) {
831                 Debug( LDAP_DEBUG_ANY,
832                         "<= mdb_approx_candidates: (%s) "
833                         "index_param failed (%d)\n",
834                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
835                 return 0;
836         }
837
838         mr = ava->aa_desc->ad_type->sat_approx;
839         if( !mr ) {
840                 /* no approx matching rule, try equality matching rule */
841                 mr = ava->aa_desc->ad_type->sat_equality;
842         }
843
844         if( !mr ) {
845                 return 0;
846         }
847
848         if( !mr->smr_filter ) {
849                 return 0;
850         }
851
852         rc = (mr->smr_filter)(
853                 LDAP_FILTER_APPROX,
854                 mask,
855                 ava->aa_desc->ad_type->sat_syntax,
856                 mr,
857                 &prefix,
858                 &ava->aa_value,
859                 &keys, op->o_tmpmemctx );
860
861         if( rc != LDAP_SUCCESS ) {
862                 Debug( LDAP_DEBUG_TRACE,
863                         "<= mdb_approx_candidates: (%s, %s) "
864                         "MR filter failed (%d)\n",
865                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
866                 return 0;
867         }
868
869         if( keys == NULL ) {
870                 Debug( LDAP_DEBUG_TRACE,
871                         "<= mdb_approx_candidates: (%s) no keys (%s)\n",
872                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, 0 );
873                 return 0;
874         }
875
876         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
877                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
878
879                 if( rc == MDB_NOTFOUND ) {
880                         MDB_IDL_ZERO( ids );
881                         rc = 0;
882                         break;
883                 } else if( rc != LDAP_SUCCESS ) {
884                         Debug( LDAP_DEBUG_TRACE,
885                                 "<= mdb_approx_candidates: (%s) "
886                                 "key read failed (%d)\n",
887                                 ava->aa_desc->ad_cname.bv_val, rc, 0 );
888                         break;
889                 }
890
891                 if( MDB_IDL_IS_ZERO( tmp ) ) {
892                         Debug( LDAP_DEBUG_TRACE,
893                                 "<= mdb_approx_candidates: (%s) NULL\n",
894                                 ava->aa_desc->ad_cname.bv_val, 0, 0 );
895                         MDB_IDL_ZERO( ids );
896                         break;
897                 }
898
899                 if ( i == 0 ) {
900                         MDB_IDL_CPY( ids, tmp );
901                 } else {
902                         mdb_idl_intersection( ids, tmp );
903                 }
904
905                 if( MDB_IDL_IS_ZERO( ids ) )
906                         break;
907         }
908
909         ber_bvarray_free_x( keys, op->o_tmpmemctx );
910
911         Debug( LDAP_DEBUG_TRACE, "<= mdb_approx_candidates %ld, first=%ld, last=%ld\n",
912                 (long) ids[0],
913                 (long) MDB_IDL_FIRST(ids),
914                 (long) MDB_IDL_LAST(ids) );
915         return( rc );
916 }
917
918 static int
919 substring_candidates(
920         Operation *op,
921         MDB_txn *rtxn,
922         SubstringsAssertion     *sub,
923         ID *ids,
924         ID *tmp )
925 {
926         MDB_dbi dbi;
927         int i;
928         int rc;
929         slap_mask_t mask;
930         struct berval prefix = {0, NULL};
931         struct berval *keys = NULL;
932         MatchingRule *mr;
933
934         Debug( LDAP_DEBUG_TRACE, "=> mdb_substring_candidates (%s)\n",
935                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
936
937         MDB_IDL_ALL( ids );
938
939         rc = mdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS,
940                 &dbi, &mask, &prefix );
941
942         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
943                 Debug( LDAP_DEBUG_ANY,
944                         "<= mdb_substring_candidates: (%s) not indexed\n",
945                         sub->sa_desc->ad_cname.bv_val, 0, 0 );
946                 return 0;
947         }
948
949         if( rc != LDAP_SUCCESS ) {
950                 Debug( LDAP_DEBUG_ANY,
951                         "<= mdb_substring_candidates: (%s) "
952                         "index_param failed (%d)\n",
953                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
954                 return 0;
955         }
956
957         mr = sub->sa_desc->ad_type->sat_substr;
958
959         if( !mr ) {
960                 return 0;
961         }
962
963         if( !mr->smr_filter ) {
964                 return 0;
965         }
966
967         rc = (mr->smr_filter)(
968                 LDAP_FILTER_SUBSTRINGS,
969                 mask,
970                 sub->sa_desc->ad_type->sat_syntax,
971                 mr,
972                 &prefix,
973                 sub,
974                 &keys, op->o_tmpmemctx );
975
976         if( rc != LDAP_SUCCESS ) {
977                 Debug( LDAP_DEBUG_TRACE,
978                         "<= mdb_substring_candidates: (%s) "
979                         "MR filter failed (%d)\n",
980                         sub->sa_desc->ad_cname.bv_val, rc, 0 );
981                 return 0;
982         }
983
984         if( keys == NULL ) {
985                 Debug( LDAP_DEBUG_TRACE,
986                         "<= mdb_substring_candidates: (0x%04lx) no keys (%s)\n",
987                         mask, sub->sa_desc->ad_cname.bv_val, 0 );
988                 return 0;
989         }
990
991         for ( i= 0; keys[i].bv_val != NULL; i++ ) {
992                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 );
993
994                 if( rc == MDB_NOTFOUND ) {
995                         MDB_IDL_ZERO( ids );
996                         rc = 0;
997                         break;
998                 } else if( rc != LDAP_SUCCESS ) {
999                         Debug( LDAP_DEBUG_TRACE,
1000                                 "<= mdb_substring_candidates: (%s) "
1001                                 "key read failed (%d)\n",
1002                                 sub->sa_desc->ad_cname.bv_val, rc, 0 );
1003                         break;
1004                 }
1005
1006                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1007                         Debug( LDAP_DEBUG_TRACE,
1008                                 "<= mdb_substring_candidates: (%s) NULL\n",
1009                                 sub->sa_desc->ad_cname.bv_val, 0, 0 );
1010                         MDB_IDL_ZERO( ids );
1011                         break;
1012                 }
1013
1014                 if ( i == 0 ) {
1015                         MDB_IDL_CPY( ids, tmp );
1016                 } else {
1017                         mdb_idl_intersection( ids, tmp );
1018                 }
1019
1020                 if( MDB_IDL_IS_ZERO( ids ) )
1021                         break;
1022         }
1023
1024         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1025
1026         Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: %ld, first=%ld, last=%ld\n",
1027                 (long) ids[0],
1028                 (long) MDB_IDL_FIRST(ids),
1029                 (long) MDB_IDL_LAST(ids) );
1030         return( rc );
1031 }
1032
1033 static int
1034 inequality_candidates(
1035         Operation *op,
1036         MDB_txn *rtxn,
1037         AttributeAssertion *ava,
1038         ID *ids,
1039         ID *tmp,
1040         int gtorlt )
1041 {
1042         MDB_dbi dbi;
1043         int rc;
1044         slap_mask_t mask;
1045         struct berval prefix = {0, NULL};
1046         struct berval *keys = NULL;
1047         MatchingRule *mr;
1048         MDB_cursor *cursor = NULL;
1049
1050         Debug( LDAP_DEBUG_TRACE, "=> mdb_inequality_candidates (%s)\n",
1051                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1052
1053         MDB_IDL_ALL( ids );
1054
1055         rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
1056                 &dbi, &mask, &prefix );
1057
1058         if ( rc == LDAP_INAPPROPRIATE_MATCHING ) {
1059                 Debug( LDAP_DEBUG_ANY,
1060                         "<= mdb_inequality_candidates: (%s) not indexed\n", 
1061                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1062                 return 0;
1063         }
1064
1065         if( rc != LDAP_SUCCESS ) {
1066                 Debug( LDAP_DEBUG_ANY,
1067                         "<= mdb_inequality_candidates: (%s) "
1068                         "index_param failed (%d)\n",
1069                         ava->aa_desc->ad_cname.bv_val, rc, 0 );
1070                 return 0;
1071         }
1072
1073         mr = ava->aa_desc->ad_type->sat_equality;
1074         if( !mr ) {
1075                 return 0;
1076         }
1077
1078         if( !mr->smr_filter ) {
1079                 return 0;
1080         }
1081
1082         rc = (mr->smr_filter)(
1083                 LDAP_FILTER_EQUALITY,
1084                 mask,
1085                 ava->aa_desc->ad_type->sat_syntax,
1086                 mr,
1087                 &prefix,
1088                 &ava->aa_value,
1089                 &keys, op->o_tmpmemctx );
1090
1091         if( rc != LDAP_SUCCESS ) {
1092                 Debug( LDAP_DEBUG_TRACE,
1093                         "<= mdb_inequality_candidates: (%s, %s) "
1094                         "MR filter failed (%d)\n",
1095                         prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
1096                 return 0;
1097         }
1098
1099         if( keys == NULL ) {
1100                 Debug( LDAP_DEBUG_TRACE,
1101                         "<= mdb_inequality_candidates: (%s) no keys\n",
1102                         ava->aa_desc->ad_cname.bv_val, 0, 0 );
1103                 return 0;
1104         }
1105
1106         MDB_IDL_ZERO( ids );
1107         while(1) {
1108                 rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[0], tmp, &cursor, gtorlt );
1109
1110                 if( rc == MDB_NOTFOUND ) {
1111                         rc = 0;
1112                         break;
1113                 } else if( rc != LDAP_SUCCESS ) {
1114                         Debug( LDAP_DEBUG_TRACE,
1115                                "<= mdb_inequality_candidates: (%s) "
1116                                "key read failed (%d)\n",
1117                                ava->aa_desc->ad_cname.bv_val, rc, 0 );
1118                         break;
1119                 }
1120
1121                 if( MDB_IDL_IS_ZERO( tmp ) ) {
1122                         Debug( LDAP_DEBUG_TRACE,
1123                                "<= mdb_inequality_candidates: (%s) NULL\n", 
1124                                ava->aa_desc->ad_cname.bv_val, 0, 0 );
1125                         break;
1126                 }
1127
1128                 mdb_idl_union( ids, tmp );
1129
1130                 if( op->ors_limit && op->ors_limit->lms_s_unchecked != -1 &&
1131                         MDB_IDL_N( ids ) >= (unsigned) op->ors_limit->lms_s_unchecked ) {
1132                         mdb_cursor_close( cursor );
1133                         break;
1134                 }
1135         }
1136         ber_bvarray_free_x( keys, op->o_tmpmemctx );
1137
1138         Debug( LDAP_DEBUG_TRACE,
1139                 "<= mdb_inequality_candidates: id=%ld, first=%ld, last=%ld\n",
1140                 (long) ids[0],
1141                 (long) MDB_IDL_FIRST(ids),
1142                 (long) MDB_IDL_LAST(ids) );
1143         return( rc );
1144 }