MojErr MojDbSearchCursor::retrieveCollation(const MojDbQuery& query) { m_collation = MojDbCollationInvalid; const MojChar* orderName = query.order().data(); if (m_kindEngine && !query.order().empty()) { // Get index that is set by orderBy MojDbKind* kind = NULL; MojErr err = m_kindEngine->getKind(query.from().data(), kind); MojErrCheck(err); MojDbIndex* index = kind->indexForCollation(query); if(index != NULL) { // Find property name that is equal to orderBy name form index to retrieve collation strenth. MojDbIndex::StringVec propNames = index->props(); for (MojSize idx = 0; idx < propNames.size(); idx++) { if(!(propNames.at(idx)).compare(orderName)) { m_collation = index->collation(idx); break; } } } } return MojErrNone; }
void MojoDatabase::GetAutoDownloadEmails(Signal::SlotRef slot, const MojObject& folderId, const MojInt64& rev, MojDbQuery::Page& page, MojInt32 limit) { MojDbQuery query; MojErr err = query.from(PopEmailAdapter::POP_EMAIL_KIND); ErrorToException(err); err = query.where(EmailSchema::FOLDER_ID, MojDbQuery::OpEq, folderId); ErrorToException(err); if (rev > 0) { err = query.where(PopFolderAdapter::LAST_SYNC_REV, MojDbQuery::OpGreaterThan, rev); ErrorToException(err); } query.page(page); // Sort by timestamp descending err = query.order(EmailSchema::TIMESTAMP); ErrorToException(err); query.desc(true); // Set limit if(limit > 0) { query.limit(limit); } slot.cancel(); err = m_dbClient.find(slot, query); ErrorToException(err); }
MojErr MojDbDistinctTest::initQuery(MojDbQuery& query, const MojChar* queryString) { query.clear(); MojErr err = query.from(_T("DistinctTest:1")); MojTestErrCheck(err); err = query.distinct(queryString); MojTestErrCheck(err); err = query.order(queryString); MojTestErrCheck(err); return MojErrNone; }
void MojoDatabase::GetEmails(Signal::SlotRef slot, const MojObject& folderId, MojInt32 limit) { MojDbQuery q; MojErr err = q.from(PopEmailAdapter::POP_EMAIL_KIND); ErrorToException(err); err = q.where(EmailSchema::FOLDER_ID, MojDbQuery::OpEq, folderId); ErrorToException(err); err = q.order(EmailSchema::TIMESTAMP); ErrorToException(err); q.limit(limit); q.desc(true); err = m_dbClient.find(slot, q); ErrorToException(err); }
void MojoDatabase::GetEmailSyncList(Signal::SlotRef slot, const MojObject& folderId, const MojInt64& rev, bool desc, MojDbQuery::Page& page, MojInt32 limit) { MojErr err; MojDbQuery query; err = query.from(PopEmailAdapter::POP_EMAIL_KIND);//EmailSchema::Kind::EMAIL); ErrorToException(err); // Select relevant fields err = query.select(PopEmailAdapter::ID); ErrorToException(err); err = query.select(PopEmailAdapter::SERVER_UID); ErrorToException(err); err = query.select(EmailSchema::TIMESTAMP); ErrorToException(err); err = query.where(EmailSchema::FOLDER_ID, MojDbQuery::OpEq, folderId); ErrorToException(err); if (rev > 0) { err = query.where(PopFolderAdapter::LAST_SYNC_REV, MojDbQuery::OpGreaterThan, rev); ErrorToException(err); } query.page(page); // Sort by timestamp descending err = query.order(EmailSchema::TIMESTAMP); ErrorToException(err); query.desc(desc); // Set limit if(limit > 0) { query.limit(limit); } slot.cancel(); // cancel existing slot in case we're in a callback err = m_dbClient.find(slot, query); ErrorToException(err); }
MojErr MojDbSearchTest::initQuery(MojDbQuery& query, const MojChar* queryStr, const MojChar* orderBy, const MojObject& barVal, bool desc) { query.clear(); MojErr err = query.from(_T("SearchTest:1")); MojTestErrCheck(err); MojString val; err = val.assign(queryStr); MojTestErrCheck(err); err = query.where(_T("foo"), MojDbQuery::OpSearch, val, MojDbCollationPrimary); MojTestErrCheck(err); query.desc(desc); if (!barVal.undefined()) { err = query.where(_T("bar"), MojDbQuery::OpEq, barVal); MojTestErrCheck(err); } if (orderBy) { err = query.order(orderBy); MojTestErrCheck(err); } return MojErrNone; }
MojErr MojDbSearchCursor::init(const MojDbQuery& query) { MojErr err = initImpl(query); MojErrCheck(err); err = retrieveCollation(query); MojErrCheck(err); // override limit and sort since we need to retrieve everything // and sort before re-imposing limit m_limit = query.limit(); m_distinct = query.distinct(); if (!m_distinct.empty()) { m_orderProp = m_distinct; } else { m_orderProp = query.order(); } m_query.limit(MaxResults); err = m_query.order(_T("")); MojErrCheck(err); return MojErrNone; }
MojErr MojDbSearchCursor::init(const MojDbQuery& query) { LOG_TRACE("Entering function %s", __FUNCTION__); MojErr err = initImpl(query); MojErrCheck(err); err = retrieveCollation(query); MojErrCheck(err); // override limit and sort since we need to retrieve everything // and sort before re-imposing limit m_limit = query.limit(); m_distinct = query.distinct(); if (!m_distinct.empty()) { m_orderProp = m_distinct; } else { m_orderProp = query.order(); } // retrieve page info from query. MojDbQuery::Page page; page = m_query.page(); if(!page.empty()) { MojObject objOut; err = page.toObject(objOut); MojErrCheck(err); m_page.fromObject(objOut); } m_query.limit(MaxResults); err = m_query.order(_T("")); MojErrCheck(err); // delete page info from query for query plan page.clear(); m_query.page(page); return MojErrNone; }
bool MojDbIndex::canAnswer(const MojDbQuery& query) const { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(isOpen()); MojAssert(!m_propNames.empty()); // if this index is not ready yet, return false if (!m_ready) return false; // The goal here is to figure out whether the results for the query are contiguous in // the index. That will be the case if all the props referenced are contiguous in our // prop vector, any prop referenced by an inequality op comes at the end of the // range of referenced props, any unreferenced props in our vector are at the end, // and the order prop is either the last referenced prop or, if all ops are equality ops, // the prop following the last referenced prop. const MojDbQuery::WhereMap& map = query.where(); MojSize numQueryProps = map.size(); // if there are more props in the query than in our index, no can do if (numQueryProps > m_propNames.size()) return false; // skip the first prop if we have an incDel index and the query does not reference the del prop StringVec::ConstIterator propName = m_propNames.begin(); PropVec::ConstIterator prop = m_props.begin(); if (m_includeDeleted && !map.contains(MojDb::DelKey)) { ++propName; ++prop; } // if there are no props in query, but the order matches our first prop, we're good const MojString& orderProp = query.order(); if (numQueryProps == 0) { if (orderProp.empty()) { return isIdIndex(); } else { return *propName == orderProp; } } // check all remaining props for (; propName != m_propNames.end(); ++propName, ++prop) { --numQueryProps; // ensure that the current prop is referenced in the query (no gaps) MojDbQuery::WhereMap::ConstIterator mapIter = map.find(*propName); if (mapIter == map.end()) return false; // ensure that if it is an inequality op, it is at the end if (numQueryProps > 0 && mapIter->lowerOp() != MojDbQuery::OpEq) return false; // ensure that collation matches if (mapIter->collation() != (*prop)->collation()) return false; // hooray, we made it through all the props in the query without failing any tests. // there may still be unreferenced props at the end of the vector, but that's ok. if (numQueryProps == 0) { // make sure that we can satisfy the ordering. if there is no ordering, or we are // ordering on a referenced prop, we're golden if (!orderProp.empty() && !map.contains(orderProp)) { // ensure that the order prop is next in our vec StringVec::ConstIterator next = propName + 1; if (next == m_propNames.end() || *next != orderProp) return false; } // can do! return true; } } return false; }
MojErr MojDb::purge(MojUInt32& countOut, MojInt64 numDays, MojDbReqRef req) { MojLogTrace(s_log); countOut = 0; if (numDays <= -1) { numDays = m_purgeWindow; } MojErr err = beginReq(req); MojErrCheck(err); MojLogDebug(s_log, _T("purging objects deleted more than %lld days ago..."), numDays); MojTime time; err = MojGetCurrentTime(time); MojErrCheck(err); // store the revision number to current timestamp mapping MojObject revTimeMapping; MojInt64 rev; err = nextId(rev); MojErrCheck(err); err = revTimeMapping.put(RevNumKey, rev); MojErrCheck(err); err = revTimeMapping.put(TimestampKey, time.microsecs()); MojErrCheck(err); err = revTimeMapping.putString(KindKey, MojDbKindEngine::RevTimestampId); MojErrCheck(err); err = putImpl(revTimeMapping, MojDb::FlagNone, req); MojErrCheck(err); // find the revision number for numDays prior to now MojInt64 purgeTime = time.microsecs() - (MojTime::UnitsPerDay * numDays); MojDbQuery query; err = query.from(MojDbKindEngine::RevTimestampId); MojErrCheck(err); query.limit(1); err = query.where(TimestampKey, MojDbQuery::OpLessThanEq, purgeTime); MojErrCheck(err); err = query.order(TimestampKey); MojErrCheck(err); query.desc(true); MojDbCursor cursor; err = findImpl(query, cursor, NULL, req, OpDelete); MojErrCheck(err); bool found = false; MojObject obj; err = cursor.get(obj, found); MojErrCheck(err); err = cursor.close(); MojErrCheck(err); MojUInt32 batchCount = 0; MojUInt32 totalCount = 0; while ((found)) { // Do it in AutoBatchSize batches batchCount = 0; req->fixmode(true); // purge even if index mis-matches err = purgeImpl(obj, batchCount, req); MojLogDebug(s_log, _T("purge batch processed: batch: %d; total: %d; err = %d\n"), batchCount, (totalCount + batchCount), err); MojErrCheck(err); totalCount += batchCount; countOut = totalCount; if (batchCount < AutoBatchSize) // last batch break; err = commitBatch(req); MojErrCheck(err); continue; } // end request err = req->end(); MojErrCheck(err); MojLogDebug(s_log, _T("purged %d objects"), countOut); return MojErrNone; }