MojErr MojDbQueryPlan::pushSearch(MojDbKeyBuilder& lowerBuilder, MojDbKeyBuilder& upperBuilder, const MojObject& val, MojDbTextCollator* collator) { // get text MojString text; MojErr err = val.stringValue(text); MojErrCheck(err); MojDbKeyBuilder::KeySet toks; // tokenize MojRefCountedPtr<MojDbTextTokenizer> tokenizer(new MojDbTextTokenizer); MojAllocCheck(tokenizer.get()); err = tokenizer->init(m_locale); MojErrCheck(err); err = tokenizer->tokenize(text, collator, toks); MojErrCheck(err); // remove prefixes MojDbKeyBuilder::KeySet::Iterator i; err = toks.begin(i); MojErrCheck(err); MojDbKeyBuilder::KeySet::ConstIterator prev = toks.end(); while (i != toks.end()) { if (prev != toks.end() && prev->stringPrefixOf(*i)) { bool found = false; err = toks.del(*prev, found); MojErrCheck(err); MojAssert(found); } prev = i; ++i; } // push toks err = lowerBuilder.push(toks); MojErrCheck(err); err = upperBuilder.push(toks); MojErrCheck(err); m_groupCount = (MojUInt32) toks.size(); return MojErrNone; }
MojErr MojDbIndex::getKeys(const MojObject& obj, KeySet& keysOut) const { LOG_TRACE("Entering function %s", __FUNCTION__); // build the set of unique keys from object MojDbKeyBuilder builder; MojErr err = builder.push(m_idSet); MojErrCheck(err); MojSize idx = 0; for (PropVec::ConstIterator i = m_props.begin(); i != m_props.end(); ++i, ++idx) { KeySet vals; err = (*i)->vals(obj, vals); MojErrCheck(err); err = builder.push(vals); MojErrCheck(err); } err = builder.keys(keysOut); MojErrCheck(err); return MojErrNone; }
MojErr MojDbQueryPlan::pushVal(MojDbKeyBuilder& builder, const MojObject& val, MojDbTextCollator* collator) { MojErr err = MojErrNone; MojDbKey key; MojDbKeyBuilder::KeySet keys; if (val.type() == MojObject::TypeArray) { MojObject::ConstArrayIterator end = val.arrayEnd(); for (MojObject::ConstArrayIterator i = val.arrayBegin(); i != end; ++i) { err = key.assign(*i, collator); MojErrCheck(err); err = keys.put(key); MojErrCheck(err); } } else { err = key.assign(val, collator); MojErrCheck(err); err = keys.put(key); MojErrCheck(err); } err = builder.push(keys); MojErrCheck(err); return MojErrNone; }
MojErr MojDbQueryPlan::buildRanges(const MojDbIndex& index) { MojAssert(!index.props().empty()); MojErr err = MojErrNone; const MojDbQuery::WhereMap& where = m_query.where(); const StringVec& props = index.props(); const MojDbQuery::WhereClause* lastClause = NULL; MojDbKeyBuilder lowerBuilder; MojDbKeyBuilder upperBuilder; MojDbKeyBuilder::KeySet prefixKeys; err = pushVal(lowerBuilder, index.id(), NULL); MojErrCheck(err); err = pushVal(upperBuilder, index.id(), NULL); MojErrCheck(err); // push vals for all props in index prop order to create upper and lower bounds for (StringVec::ConstIterator i = props.begin(); i != props.end(); ++i) { // get clause for prop MojDbQuery::WhereMap::ConstIterator clause = where.find(*i); if (clause == where.end()) { MojAssert((MojSize)(i - props.begin()) == where.size()); break; } // create collator MojRefCountedPtr<MojDbTextCollator> collator; MojDbCollationStrength coll = clause->collation(); if (coll != MojDbCollationInvalid) { collator.reset(new MojDbTextCollator); MojAllocCheck(collator.get()); err = collator->init(m_locale, coll); MojErrCheck(err); } // push vals for clause MojDbQuery::CompOp lowerOp = clause->lowerOp(); if (lowerOp == MojDbQuery::OpSearch) { // tokenize search strings err = pushSearch(lowerBuilder, upperBuilder, clause->lowerVal(), collator.get()); MojErrCheck(err); } else { // copy off prefix before writing an inequality val if (lowerOp != MojDbQuery::OpEq && lowerOp != MojDbQuery::OpPrefix) { err = lowerBuilder.keys(prefixKeys); MojErrCheck(err); if (prefixKeys.empty()) { // if there is no prefix yet, put an empty key err = prefixKeys.put(MojDbKey()); MojErrCheck(err); } } // append lower-value to lower-key err = pushVal(lowerBuilder, clause->lowerVal(), collator.get()); MojErrCheck(err); // append appropriate value to upper-key if (clause->upperOp() == MojDbQuery::OpNone) { err = pushVal(upperBuilder, clause->lowerVal(), collator.get()); MojErrCheck(err); } else { err = pushVal(upperBuilder, clause->upperVal(), collator.get()); MojErrCheck(err); } } lastClause = &clause.value(); } // go from builders to ranges KeySet lowerKeys; err = lowerBuilder.keys(lowerKeys); MojErrCheck(err); KeySet upperKeys; err = upperBuilder.keys(upperKeys); MojErrCheck(err); if (prefixKeys.empty()) { prefixKeys = lowerKeys; } err = rangesFromKeySets(lowerKeys, upperKeys, prefixKeys, lastClause); MojErrCheck(err); return MojErrNone; }