X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=servers%2Fslapd%2Fback-mdb%2Fsearch.c;h=5cc0d28c00b5f3d0ff91f081a06f6a461a6bf97e;hb=e28793bdda900675552634a9685be8e5b7c60409;hp=624103657ae415d933eb93a487daf52247fe6e68;hpb=7d7379e8fdddbf5b7777fbdba06befd087ca30e6;p=openldap diff --git a/servers/slapd/back-mdb/search.c b/servers/slapd/back-mdb/search.c index 624103657a..5cc0d28c00 100644 --- a/servers/slapd/back-mdb/search.c +++ b/servers/slapd/back-mdb/search.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2012 The OpenLDAP Foundation. + * Copyright 2000-2013 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -98,7 +98,7 @@ static Entry * deref_base ( break; } - rs->sr_err = mdb_dn2entry( op, txn, NULL, &ndn, &e, 0 ); + rs->sr_err = mdb_dn2entry( op, txn, NULL, &ndn, &e, NULL, 0 ); if (rs->sr_err) { rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "aliasedObject not found"; @@ -218,6 +218,7 @@ static int search_aliases( */ 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 @@ -316,9 +317,10 @@ int mdb_search( Operation *op, SlapReply *rs ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; - ID id, cursor; + ID id, cursor, nsubs, ncand, cscope; ID lastid = NOID; ID candidates[MDB_IDL_UM_SIZE]; + ID iscopes[MDB_IDL_DB_SIZE]; ID2 *scopes; Entry *e = NULL, *base = NULL; Entry *matched = NULL; @@ -328,7 +330,7 @@ mdb_search( Operation *op, SlapReply *rs ) int manageDSAit; int tentries = 0; IdScopes isc; - MDB_cursor *mci; + MDB_cursor *mci, *mcd; mdb_op_info opinfo = {{{0}}}, *moi = &opinfo; MDB_txn *ltid = NULL; @@ -355,17 +357,25 @@ mdb_search( Operation *op, SlapReply *rs ) return rs->sr_err; } + rs->sr_err = mdb_cursor_open( ltid, mdb->mi_dn2id, &mcd ); + if ( rs->sr_err ) { + mdb_cursor_close( mci ); + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + return rs->sr_err; + } + scopes = scope_chunk_get( op ); isc.mt = ltid; - isc.mc = NULL; + isc.mc = mcd; isc.scopes = scopes; + isc.oscope = op->ors_scope; if ( op->ors_deref & LDAP_DEREF_FINDING ) { MDB_IDL_ZERO(candidates); } dn2entry_retry: /* get entry with reader lock */ - rs->sr_err = mdb_dn2entry( op, ltid, NULL, &op->o_req_ndn, &e, 1 ); + rs->sr_err = mdb_dn2entry( op, ltid, mcd, &op->o_req_ndn, &e, &nsubs, 1 ); switch(rs->sr_err) { case MDB_NOTFOUND: @@ -528,14 +538,42 @@ dn2entry_retry: /* select candidates */ if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) { rs->sr_err = base_candidate( op->o_bd, base, candidates ); - + scopes[0].mid = 0; + ncand = 1; } else { + if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) { + size_t nkids; + MDB_val key, data; + key.mv_data = &base->e_id; + key.mv_size = sizeof( ID ); + mdb_cursor_get( mcd, &key, &data, MDB_SET ); + mdb_cursor_count( mcd, &nkids ); + nsubs = nkids - 1; + } else if ( !base->e_id ) { + /* we don't maintain nsubs for entryID 0. + * just grab entry count from id2entry stat + */ + MDB_stat ms; + mdb_stat( ltid, mdb->mi_id2entry, &ms ); + nsubs = ms.ms_entries; + } MDB_IDL_ZERO( candidates ); scopes[0].mid = 1; scopes[1].mid = base->e_id; scopes[1].mval.mv_data = NULL; rs->sr_err = search_candidates( op, rs, base, ltid, mci, candidates, scopes ); + ncand = MDB_IDL_N( candidates ); + if ( !base->e_id || ncand == NOID ) { + /* grab entry count from id2entry stat + */ + MDB_stat ms; + mdb_stat( ltid, mdb->mi_id2entry, &ms ); + if ( !base->e_id ) + nsubs = ms.ms_entries; + if ( ncand == NOID ) + ncand = ms.ms_entries; + } } /* start cursor at beginning of candidates. @@ -553,7 +591,7 @@ dn2entry_retry: /* if not root and candidates exceed to-be-checked entries, abort */ if ( op->ors_limit /* isroot == FALSE */ && op->ors_limit->lms_s_unchecked != -1 && - MDB_IDL_N(candidates) > (unsigned) op->ors_limit->lms_s_unchecked ) + ncand > (unsigned) op->ors_limit->lms_s_unchecked ) { rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; send_ldap_result( op, rs ); @@ -564,7 +602,7 @@ dn2entry_retry: if ( op->ors_limit == NULL /* isroot == TRUE */ || !op->ors_limit->lms_s_pr_hide ) { - tentries = MDB_IDL_N(candidates); + tentries = ncand; } if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { @@ -596,11 +634,40 @@ dn2entry_retry: } if ( id == (ID)ps->ps_cookie ) id = mdb_idl_next( candidates, &cursor ); + nsubs = ncand; /* always bypass scope'd search */ goto loop_begin; } + if ( nsubs < ncand ) { + int rc; + /* Do scope-based search */ + + /* if any alias scopes were set, save them */ + if (scopes[0].mid > 1) { + cursor = 1; + for (cscope = 1; cscope <= scopes[0].mid; cscope++) { + /* Ignore the original base */ + if (scopes[cscope].mid == base->e_id) + continue; + iscopes[cursor++] = scopes[cscope].mid; + } + iscopes[0] = scopes[0].mid - 1; + } else { + iscopes[0] = 0; + } + + isc.id = base->e_id; + isc.numrdns = 0; + rc = mdb_dn2id_walk( op, &isc ); + if ( rc ) + id = NOID; + else + id = isc.id; + cscope = 0; + } else { + id = mdb_idl_first( candidates, &cursor ); + } - for ( id = mdb_idl_first( candidates, &cursor ); - id != NOID ; id = mdb_idl_next( candidates, &cursor ) ) + while (id != NOID) { int scopeok; MDB_val edata; @@ -634,41 +701,23 @@ loop_begin: goto done; } - if ( id == base->e_id ) { - e = base; - } else { - /* get the entry */ - rs->sr_err = mdb_id2edata( op, mci, id, &edata ); - if ( rs->sr_err == MDB_NOTFOUND ) { - if( !MDB_IDL_IS_RANGE(candidates) ) { - /* only complain for non-range IDLs */ - Debug( LDAP_DEBUG_TRACE, - LDAP_XSTRING(mdb_search) - ": candidate %ld not found\n", - (long) id, 0, 0 ); - } else { - /* get the next ID from the DB */ - rs->sr_err = mdb_get_nextid( mci, &cursor ); - if ( rs->sr_err == MDB_NOTFOUND ) { - break; - } - if ( rs->sr_err ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "internal error in get_nextid"; - send_ldap_result( op, rs ); - goto done; - } - cursor--; - } - - goto loop_continue; - } else if ( rs->sr_err ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "internal error in mdb_id2edata"; - send_ldap_result( op, rs ); - goto done; + if ( nsubs < ncand ) { + unsigned i; + /* Is this entry in the candidate list? */ + scopeok = 0; + if (MDB_IDL_IS_RANGE( candidates )) { + if ( id >= MDB_IDL_RANGE_FIRST( candidates ) && + id <= MDB_IDL_RANGE_LAST( candidates )) + scopeok = 1; + } else { + i = mdb_idl_search( candidates, id ); + if ( candidates[i] == id ) + scopeok = 1; } + if ( scopeok ) + goto scopeok; + goto loop_continue; } /* Does this candidate actually satisfy the search scope? @@ -694,7 +743,15 @@ loop_begin: /* Fall-thru */ case LDAP_SCOPE_ONELEVEL: isc.id = id; - if ( mdb_idscopes( op, &isc ) == MDB_SUCCESS ) scopeok = 1; + isc.nscope = 0; + rs->sr_err = mdb_idscopes( op, &isc ); + if ( rs->sr_err == MDB_SUCCESS ) { + if ( isc.nscope ) + scopeok = 1; + } else { + if ( rs->sr_err == MDB_NOTFOUND ) + goto notfound; + } break; } @@ -708,7 +765,47 @@ loop_begin: goto loop_continue; } - if ( id != base->e_id ) { +scopeok: + if ( id == base->e_id ) { + e = base; + } else { + + /* get the entry */ + rs->sr_err = mdb_id2edata( op, mci, id, &edata ); + if ( rs->sr_err == MDB_NOTFOUND ) { +notfound: + if( nsubs < ncand ) + goto loop_continue; + + if( !MDB_IDL_IS_RANGE(candidates) ) { + /* only complain for non-range IDLs */ + Debug( LDAP_DEBUG_TRACE, + LDAP_XSTRING(mdb_search) + ": candidate %ld not found\n", + (long) id, 0, 0 ); + } else { + /* get the next ID from the DB */ + rs->sr_err = mdb_get_nextid( mci, &cursor ); + if ( rs->sr_err == MDB_NOTFOUND ) { + break; + } + if ( rs->sr_err ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error in get_nextid"; + send_ldap_result( op, rs ); + goto done; + } + cursor--; + } + + goto loop_continue; + } else if ( rs->sr_err ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error in mdb_id2edata"; + send_ldap_result( op, rs ); + goto done; + } + rs->sr_err = mdb_entry_decode( op, &edata, &e ); if ( rs->sr_err ) { rs->sr_err = LDAP_OTHER; @@ -746,8 +843,7 @@ loop_begin: * deref it when finding, return it. */ if ( is_entry_alias(e) && - ((op->ors_deref & LDAP_DEREF_FINDING) || - !bvmatch(&e->e_nname, &op->o_req_ndn))) + ((op->ors_deref & LDAP_DEREF_FINDING) || e != base )) { goto loop_continue; } @@ -761,8 +857,9 @@ loop_begin: struct berval pdn, pndn; char *d, *n; int i; + /* child of base, just append RDNs to base->e_name */ - if ( isc.nscope == 1 ) { + if ( nsubs < ncand || isc.scopes[isc.nscope].mid == base->e_id ) { pdn = base->e_name; pndn = base->e_nname; } else { @@ -778,14 +875,28 @@ loop_begin: e->e_nname.bv_val = op->o_tmpalloc(e->e_nname.bv_len + 1, op->o_tmpmemctx); d = e->e_name.bv_val; n = e->e_nname.bv_val; - for (i=0; i=0; i--) { + memcpy(d, isc.rdns[i].bv_val, isc.rdns[i].bv_len); + d += isc.rdns[i].bv_len; + *d++ = ','; + memcpy(n, isc.nrdns[i].bv_val, isc.nrdns[i].bv_len); + n += isc.nrdns[i].bv_len; + *n++ = ','; + } + } else { + /* RDNs are in bottom-up order */ + for (i=0; ie_name.bv_len--; e->e_nname.bv_len--; } - if (isc.nscope != 1) { + if (pndn.bv_val != base->e_nname.bv_val) { op->o_tmpfree(pndn.bv_val, op->o_tmpmemctx); op->o_tmpfree(pdn.bv_val, op->o_tmpmemctx); } @@ -895,6 +1006,37 @@ loop_continue: e = NULL; rs->sr_entry = NULL; } + + if ( nsubs < ncand ) { + int rc = mdb_dn2id_walk( op, &isc ); + if (rc) { + id = NOID; + /* We got to the end of a subtree. If there are any + * alias scopes left, search them too. + */ + while (iscopes[0] && cscope < iscopes[0]) { + cscope++; + isc.id = iscopes[cscope]; + if ( base ) + mdb_entry_return( op, base ); + rs->sr_err = mdb_id2entry(op, mci, isc.id, &base); + if ( !rs->sr_err ) { + mdb_id2name( op, ltid, &isc.mc, isc.id, &base->e_name, &base->e_nname ); + isc.numrdns = 0; + if (isc.oscope == LDAP_SCOPE_ONELEVEL) + isc.oscope = LDAP_SCOPE_BASE; + rc = mdb_dn2id_walk( op, &isc ); + if ( !rc ) { + id = isc.id; + break; + } + } + } + } else + id = isc.id; + } else { + id = mdb_idl_next( candidates, &cursor ); + } } nochange: @@ -911,13 +1053,13 @@ nochange: rs->sr_err = LDAP_SUCCESS; done: - if( isc.mc ) - mdb_cursor_close( isc.mc ); - if (mci) - mdb_cursor_close( mci ); + mdb_cursor_close( mcd ); + mdb_cursor_close( mci ); if ( moi == &opinfo ) { mdb_txn_reset( moi->moi_txn ); LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next ); + } else { + moi->moi_ref--; } if( rs->sr_v2ref ) { ber_bvarray_free( rs->sr_v2ref );