/* Append sorted list b to sorted list a. The result is unsorted but * a[1] is the min of the result and a[a[0]] is the max. */ int mdb_idl_append( ID *a, ID *b ) { ID ida, idb, tmp, swap = 0; if ( MDB_IDL_IS_ZERO( b ) ) { return 0; } if ( MDB_IDL_IS_ZERO( a ) ) { MDB_IDL_CPY( a, b ); return 0; } ida = MDB_IDL_LAST( a ); idb = MDB_IDL_LAST( b ); if ( MDB_IDL_IS_RANGE( a ) || MDB_IDL_IS_RANGE(b) || a[0] + b[0] >= MDB_IDL_UM_MAX ) { a[2] = IDL_MAX( ida, idb ); a[1] = IDL_MIN( a[1], b[1] ); a[0] = NOID; return 0; } if ( b[0] > 1 && ida > idb ) { swap = idb; a[a[0]] = idb; b[b[0]] = ida; } if ( b[1] < a[1] ) { tmp = a[1]; a[1] = b[1]; } else { tmp = b[1]; } a[0]++; a[a[0]] = tmp; if ( b[0] > 1 ) { int i = b[0] - 1; AC_MEMCPY(a+a[0]+1, b+2, i * sizeof(ID)); a[0] += i; } if ( swap ) { b[b[0]] = swap; } return 0; }
/* * mdb_idl_notin - return a intersection ~b (or a minus b) */ int mdb_idl_notin( ID *a, ID *b, ID *ids ) { ID ida, idb; ID cursora = 0, cursorb = 0; if( MDB_IDL_IS_ZERO( a ) || MDB_IDL_IS_ZERO( b ) || MDB_IDL_IS_RANGE( b ) ) { MDB_IDL_CPY( ids, a ); return 0; } if( MDB_IDL_IS_RANGE( a ) ) { MDB_IDL_CPY( ids, a ); return 0; } ida = mdb_idl_first( a, &cursora ), idb = mdb_idl_first( b, &cursorb ); ids[0] = 0; while( ida != NOID ) { if ( idb == NOID ) { /* we could shortcut this */ ids[++ids[0]] = ida; ida = mdb_idl_next( a, &cursora ); } else if ( ida < idb ) { ids[++ids[0]] = ida; ida = mdb_idl_next( a, &cursora ); } else if ( ida > idb ) { idb = mdb_idl_next( b, &cursorb ); } else { ida = mdb_idl_next( a, &cursora ); idb = mdb_idl_next( b, &cursorb ); } } return 0; }
static int substring_candidates( Operation *op, MDB_txn *rtxn, SubstringsAssertion *sub, ID *ids, ID *tmp ) { MDB_dbi dbi; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr; Debug( LDAP_DEBUG_TRACE, "=> mdb_substring_candidates (%s)\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); MDB_IDL_ALL( ids ); rc = mdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS, &dbi, &mask, &prefix ); if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, "<= mdb_substring_candidates: (%s) not indexed\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); return 0; } if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "<= mdb_substring_candidates: (%s) " "index_param failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); return 0; } mr = sub->sa_desc->ad_type->sat_substr; if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (mr->smr_filter)( LDAP_FILTER_SUBSTRINGS, mask, sub->sa_desc->ad_type->sat_syntax, mr, &prefix, sub, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: (%s) " "MR filter failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); return 0; } if( keys == NULL ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: (0x%04lx) no keys (%s)\n", mask, sub->sa_desc->ad_cname.bv_val, 0 ); return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 ); if( rc == MDB_NOTFOUND ) { MDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: (%s) " "key read failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); break; } if( MDB_IDL_IS_ZERO( tmp ) ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: (%s) NULL\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); MDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { MDB_IDL_CPY( ids, tmp ); } else { mdb_idl_intersection( ids, tmp ); } if( MDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= mdb_substring_candidates: %ld, first=%ld, last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); return( rc ); }
static int equality_candidates( Operation *op, MDB_txn *rtxn, AttributeAssertion *ava, ID *ids, ID *tmp ) { MDB_dbi dbi; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr; Debug( LDAP_DEBUG_TRACE, "=> mdb_equality_candidates (%s)\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { ID id; rc = mdb_dn2id( op, rtxn, NULL, &ava->aa_value, &id, NULL, NULL, NULL ); if ( rc == LDAP_SUCCESS ) { /* exactly one ID can match */ ids[0] = 1; ids[1] = id; } if ( rc == MDB_NOTFOUND ) { MDB_IDL_ZERO( ids ); rc = 0; } return rc; } MDB_IDL_ALL( ids ); rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY, &dbi, &mask, &prefix ); if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, "<= mdb_equality_candidates: (%s) not indexed\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "<= mdb_equality_candidates: (%s) " "index_param failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } mr = ava->aa_desc->ad_type->sat_equality; if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (mr->smr_filter)( LDAP_FILTER_EQUALITY, mask, ava->aa_desc->ad_type->sat_syntax, mr, &prefix, &ava->aa_value, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_equality_candidates: (%s, %s) " "MR filter failed (%d)\n", prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc ); return 0; } if( keys == NULL ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_equality_candidates: (%s) no keys\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 ); if( rc == MDB_NOTFOUND ) { MDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_equality_candidates: (%s) " "key read failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); break; } if( MDB_IDL_IS_ZERO( tmp ) ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_equality_candidates: (%s) NULL\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); MDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { MDB_IDL_CPY( ids, tmp ); } else { mdb_idl_intersection( ids, tmp ); } if( MDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= mdb_equality_candidates: id=%ld, first=%ld, last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); return( rc ); }
static int list_candidates( Operation *op, MDB_txn *rtxn, Filter *flist, int ftype, ID *ids, ID *tmp, ID *save ) { int rc = 0; Filter *f; Debug( LDAP_DEBUG_FILTER, "=> mdb_list_candidates 0x%x\n", ftype, 0, 0 ); for ( f = flist; f != NULL; f = f->f_next ) { /* ignore precomputed scopes */ if ( f->f_choice == SLAPD_FILTER_COMPUTED && f->f_result == LDAP_SUCCESS ) { continue; } MDB_IDL_ZERO( save ); rc = mdb_filter_candidates( op, rtxn, f, save, tmp, save+MDB_IDL_UM_SIZE ); if ( rc != 0 ) { if ( ftype == LDAP_FILTER_AND ) { rc = 0; continue; } break; } if ( ftype == LDAP_FILTER_AND ) { if ( f == flist ) { MDB_IDL_CPY( ids, save ); } else { mdb_idl_intersection( ids, save ); } if( MDB_IDL_IS_ZERO( ids ) ) break; } else { if ( f == flist ) { MDB_IDL_CPY( ids, save ); } else { mdb_idl_union( ids, save ); } } } if( rc == LDAP_SUCCESS ) { Debug( LDAP_DEBUG_FILTER, "<= mdb_list_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); } else { Debug( LDAP_DEBUG_FILTER, "<= mdb_list_candidates: undefined rc=%d\n", rc, 0, 0 ); } return rc; }
static int comp_equality_candidates ( Operation *op, MDB_txn *rtxn, MatchingRuleAssertion *mra, ComponentAssertion *ca, ID *ids, ID *tmp, ID *stack) { MDB_dbi dbi; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr = mra->ma_rule; Syntax *sat_syntax; ComponentReference* cr_list, *cr; AttrInfo *ai; MDB_IDL_ALL( ids ); if ( !ca->ca_comp_ref ) return 0; ai = mdb_attr_mask( op->o_bd->be_private, mra->ma_desc ); if( ai ) { cr_list = ai->ai_cr; } else { return 0; } /* find a component reference to be indexed */ sat_syntax = ca->ca_ma_rule->smr_syntax; for ( cr = cr_list ; cr ; cr = cr->cr_next ) { if ( cr->cr_string.bv_len == ca->ca_comp_ref->cr_string.bv_len && strncmp( cr->cr_string.bv_val, ca->ca_comp_ref->cr_string.bv_val,cr->cr_string.bv_len ) == 0 ) break; } if ( !cr ) return 0; rc = mdb_index_param( op->o_bd, mra->ma_desc, LDAP_FILTER_EQUALITY, &dbi, &mask, &prefix ); if( rc != LDAP_SUCCESS ) { return 0; } if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (ca->ca_ma_rule->smr_filter)( LDAP_FILTER_EQUALITY, cr->cr_indexmask, sat_syntax, ca->ca_ma_rule, &prefix, &ca->ca_ma_value, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { return 0; } if( keys == NULL ) { return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[i], tmp, NULL, 0 ); if( rc == MDB_NOTFOUND ) { MDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { break; } if( MDB_IDL_IS_ZERO( tmp ) ) { MDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { MDB_IDL_CPY( ids, tmp ); } else { mdb_idl_intersection( ids, tmp ); } if( MDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= comp_equality_candidates: id=%ld, first=%ld, last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); return( rc ); }
static int inequality_candidates( Operation *op, MDB_txn *rtxn, AttributeAssertion *ava, ID *ids, ID *tmp, int gtorlt ) { MDB_dbi dbi; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr; MDB_cursor *cursor = NULL; Debug( LDAP_DEBUG_TRACE, "=> mdb_inequality_candidates (%s)\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); MDB_IDL_ALL( ids ); rc = mdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY, &dbi, &mask, &prefix ); if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, "<= mdb_inequality_candidates: (%s) not indexed\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "<= mdb_inequality_candidates: (%s) " "index_param failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } mr = ava->aa_desc->ad_type->sat_equality; if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (mr->smr_filter)( LDAP_FILTER_EQUALITY, mask, ava->aa_desc->ad_type->sat_syntax, mr, &prefix, &ava->aa_value, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_inequality_candidates: (%s, %s) " "MR filter failed (%d)\n", prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc ); return 0; } if( keys == NULL ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_inequality_candidates: (%s) no keys\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } MDB_IDL_ZERO( ids ); while(1) { rc = mdb_key_read( op->o_bd, rtxn, dbi, &keys[0], tmp, &cursor, gtorlt ); if( rc == MDB_NOTFOUND ) { rc = 0; break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_inequality_candidates: (%s) " "key read failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); break; } if( MDB_IDL_IS_ZERO( tmp ) ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_inequality_candidates: (%s) NULL\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); break; } mdb_idl_union( ids, tmp ); if( op->ors_limit && op->ors_limit->lms_s_unchecked != -1 && MDB_IDL_N( ids ) >= (unsigned) op->ors_limit->lms_s_unchecked ) { mdb_cursor_close( cursor ); break; } } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= mdb_inequality_candidates: id=%ld, first=%ld, last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); return( rc ); }
/* Look for and dereference all aliases within the search scope. * Requires "stack" to be able to hold 6 levels of DB_SIZE IDLs. * Of course we're hardcoded to require a minimum of 8 UM_SIZE * IDLs so this is never a problem. */ static int search_aliases( Operation *op, SlapReply *rs, ID e_id, IdScopes *isc, MDB_cursor *mci, ID *stack ) { ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp; ID cursora, ida, cursoro, ido; Entry *matched, *a; struct berval bv_alias = BER_BVC( "alias" ); AttributeAssertion aa_alias = ATTRIBUTEASSERTION_INIT; Filter af; int first = 1; aliases = stack; /* IDL of all aliases in the database */ curscop = aliases + MDB_IDL_DB_SIZE; /* Aliases in the current scope */ visited = curscop + MDB_IDL_DB_SIZE; /* IDs we've seen in this search */ newsubs = visited + MDB_IDL_DB_SIZE; /* New subtrees we've added */ oldsubs = newsubs + MDB_IDL_DB_SIZE; /* Subtrees added previously */ tmp = oldsubs + MDB_IDL_DB_SIZE; /* Scratch space for deref_base() */ af.f_choice = LDAP_FILTER_EQUALITY; af.f_ava = &aa_alias; af.f_av_desc = slap_schema.si_ad_objectClass; af.f_av_value = bv_alias; af.f_next = NULL; /* Find all aliases in database */ MDB_IDL_ZERO( aliases ); rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases, curscop, visited ); if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) { return rs->sr_err; } oldsubs[0] = 1; oldsubs[1] = e_id; MDB_IDL_ZERO( visited ); MDB_IDL_ZERO( newsubs ); cursoro = 0; ido = mdb_idl_first( oldsubs, &cursoro ); for (;;) { /* Set curscop to only the aliases in the current scope. Start with * all the aliases, then get the intersection with the scope. */ rs->sr_err = mdb_idscope( op, isc->mt, e_id, aliases, curscop ); /* Dereference all of the aliases in the current scope. */ cursora = 0; for (ida = mdb_idl_first(curscop, &cursora); ida != NOID; ida = mdb_idl_next(curscop, &cursora)) { rs->sr_err = mdb_id2entry(op, mci, ida, &a); if (rs->sr_err != LDAP_SUCCESS) { continue; } /* This should only happen if the curscop IDL has maxed out and * turned into a range that spans IDs indiscriminately */ if (!is_entry_alias(a)) { mdb_entry_return(op, a); continue; } /* Actually dereference the alias */ MDB_IDL_ZERO(tmp); a = deref_base( op, rs, a, &matched, isc->mt, tmp, visited ); if (a) { /* If the target was not already in our current scopes, * make note of it in the newsubs list. */ ID2 mid; mid.mid = a->e_id; mid.mval.mv_data = NULL; if (op->ors_scope == LDAP_SCOPE_SUBTREE) { isc->id = a->e_id; /* if ID is a child of any of our current scopes, * ignore it, it's already included. */ if (mdb_idscopechk(op, isc)) goto skip; } if (mdb_id2l_insert(isc->scopes, &mid) == 0) { mdb_idl_insert(newsubs, a->e_id); } skip: mdb_entry_return( op, a ); } else if (matched) { /* Alias could not be dereferenced, or it deref'd to * an ID we've already seen. Ignore it. */ mdb_entry_return( op, matched ); rs->sr_text = NULL; rs->sr_err = 0; } } /* If this is a OneLevel search, we're done; oldsubs only had one * ID in it. For a Subtree search, oldsubs may be a list of scope IDs. */ if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break; nextido: ido = mdb_idl_next( oldsubs, &cursoro ); /* If we're done processing the old scopes, did we add any new * scopes in this iteration? If so, go back and do those now. */ if (ido == NOID) { if (MDB_IDL_IS_ZERO(newsubs)) break; MDB_IDL_CPY(oldsubs, newsubs); MDB_IDL_ZERO(newsubs); cursoro = 0; ido = mdb_idl_first( oldsubs, &cursoro ); } /* Find the entry corresponding to the next scope. If it can't * be found, ignore it and move on. This should never happen; * we should never see the ID of an entry that doesn't exist. */ { MDB_val edata; rs->sr_err = mdb_id2edata(op, mci, ido, &edata); if ( rs->sr_err != MDB_SUCCESS ) { goto nextido; } e_id = ido; } } return rs->sr_err; }
/* * idl_union - return a = a union b */ int mdb_idl_union( ID *a, ID *b ) { ID ida, idb; ID cursora = 0, cursorb = 0, cursorc; if ( MDB_IDL_IS_ZERO( b ) ) { return 0; } if ( MDB_IDL_IS_ZERO( a ) ) { MDB_IDL_CPY( a, b ); return 0; } if ( MDB_IDL_IS_RANGE( a ) || MDB_IDL_IS_RANGE(b) ) { over: ida = IDL_MIN( MDB_IDL_FIRST(a), MDB_IDL_FIRST(b) ); idb = IDL_MAX( MDB_IDL_LAST(a), MDB_IDL_LAST(b) ); a[0] = NOID; a[1] = ida; a[2] = idb; return 0; } ida = mdb_idl_first( a, &cursora ); idb = mdb_idl_first( b, &cursorb ); cursorc = b[0]; /* The distinct elements of a are cat'd to b */ while( ida != NOID || idb != NOID ) { if ( ida < idb ) { if( ++cursorc > MDB_IDL_UM_MAX ) { goto over; } b[cursorc] = ida; ida = mdb_idl_next( a, &cursora ); } else { if ( ida == idb ) ida = mdb_idl_next( a, &cursora ); idb = mdb_idl_next( b, &cursorb ); } } /* b is copied back to a in sorted order */ a[0] = cursorc; cursora = 1; cursorb = 1; cursorc = b[0]+1; while (cursorb <= b[0] || cursorc <= a[0]) { if (cursorc > a[0]) idb = NOID; else idb = b[cursorc]; if (cursorb <= b[0] && b[cursorb] < idb) a[cursora++] = b[cursorb++]; else { a[cursora++] = idb; cursorc++; } } return 0; }
/* * idl_intersection - return a = a intersection b */ int mdb_idl_intersection( ID *a, ID *b ) { ID ida, idb; ID idmax, idmin; ID cursora = 0, cursorb = 0, cursorc; int swap = 0; if ( MDB_IDL_IS_ZERO( a ) || MDB_IDL_IS_ZERO( b ) ) { a[0] = 0; return 0; } idmin = IDL_MAX( MDB_IDL_FIRST(a), MDB_IDL_FIRST(b) ); idmax = IDL_MIN( MDB_IDL_LAST(a), MDB_IDL_LAST(b) ); if ( idmin > idmax ) { a[0] = 0; return 0; } else if ( idmin == idmax ) { a[0] = 1; a[1] = idmin; return 0; } if ( MDB_IDL_IS_RANGE( a ) ) { if ( MDB_IDL_IS_RANGE(b) ) { /* If both are ranges, just shrink the boundaries */ a[1] = idmin; a[2] = idmax; return 0; } else { /* Else swap so that b is the range, a is a list */ ID *tmp = a; a = b; b = tmp; swap = 1; } } /* If a range completely covers the list, the result is * just the list. If idmin to idmax is contiguous, just * turn it into a range. */ if ( MDB_IDL_IS_RANGE( b ) && MDB_IDL_RANGE_FIRST( b ) <= MDB_IDL_RANGE_FIRST( a ) && MDB_IDL_RANGE_LAST( b ) >= MDB_IDL_RANGE_LAST( a ) ) { if (idmax - idmin + 1 == a[0]) { a[0] = NOID; a[1] = idmin; a[2] = idmax; } goto done; } /* Fine, do the intersection one element at a time. * First advance to idmin in both IDLs. */ cursora = cursorb = idmin; ida = mdb_idl_first( a, &cursora ); idb = mdb_idl_first( b, &cursorb ); cursorc = 0; while( ida <= idmax || idb <= idmax ) { if( ida == idb ) { a[++cursorc] = ida; ida = mdb_idl_next( a, &cursora ); idb = mdb_idl_next( b, &cursorb ); } else if ( ida < idb ) { ida = mdb_idl_next( a, &cursora ); } else { idb = mdb_idl_next( b, &cursorb ); } } a[0] = cursorc; done: if (swap) MDB_IDL_CPY( b, a ); return 0; }