bdb_query.cpp
来自「ncbi源码」· C++ 代码 · 共 1,189 行 · 第 1/2 页
CPP
1,189 行
/* * =========================================================================== * PRODUCTION $Log: bdb_query.cpp,v $ * PRODUCTION Revision 1000.1 2004/06/01 18:37:29 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13 * PRODUCTION * =========================================================================== *//* $Id: bdb_query.cpp,v 1000.1 2004/06/01 18:37:29 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Anatoliy Kuznetsov * * File Description: BDB libarary query implementation * */#include <ncbi_pch.hpp>#include <bdb/bdb_query.hpp>#include <bdb/bdb_cursor.hpp>#include <bdb/bdb_util.hpp>#include <util/resource_pool.hpp>#include <util/strsearch.hpp>BEGIN_NCBI_SCOPE/////////////////////////////////////////////////////////////////////////////// CBDB_QueryNode//CBDB_QueryNode::CBDB_QueryNode(string value) : m_NodeType(eValue), m_Value(value){}CBDB_QueryNode::CBDB_QueryNode(ELogicalType ltype) : m_NodeType(eLogical){ m_SubType.LogicalType = ltype;}CBDB_QueryNode::CBDB_QueryNode(EOperatorType otype, bool not_flag) : m_NodeType(eOperator), m_NotFlag(not_flag){ m_SubType.OperatorType = otype;}CBDB_QueryNode::CBDB_QueryNode(const CBDB_QueryNode& qnode){ m_NodeType = qnode.m_NodeType; m_Value = qnode.m_Value; m_SubType.LogicalType = qnode.m_SubType.LogicalType; m_NotFlag = qnode.m_NotFlag;}CBDB_QueryNode& CBDB_QueryNode::operator=(const CBDB_QueryNode& qnode){ m_NodeType = qnode.m_NodeType; m_Value = qnode.m_Value; m_SubType.LogicalType = qnode.m_SubType.LogicalType; m_NotFlag = qnode.m_NotFlag; return *this;}CBDB_QueryNode::~CBDB_QueryNode(){}CBDB_QueryNode::ELogicalType CBDB_QueryNode::GetLogicType() const{ if (m_NodeType == eLogical) { return m_SubType.LogicalType; } // Caller asking to get sub-type as logical when the node type is not BDB_THROW(eQueryError, "Incorrect query node type");}CBDB_QueryNode::EOperatorType CBDB_QueryNode::GetOperatorType() const{ if (m_NodeType == eOperator) { return m_SubType.OperatorType; } // Caller asking to get sub-type as operator when the node type is not BDB_THROW(eQueryError, "Incorrect query node type");}void CBDB_QueryNode::SetField(int field_idx){ m_NodeType = eDBField; m_SubType.FieldIdx = field_idx;}/////////////////////////////////////////////////////////////////////////////// CBDB_Query//CBDB_Query::CBDB_Query(TQueryClause* qc){ if (qc) { m_QueryClause = qc; } else { m_QueryClause = new TQueryClause; }}CBDB_Query::~CBDB_Query(){ delete m_QueryClause;}/// Reset all intermidiate results of tree evaluation (values)/// value constants will not be destroyedstatic ETreeTraverseCode s_ResetQueryNode(CTreeNode<CBDB_QueryNode>& tr, int delta){ if (delta < 0) return eTreeTraverse; CBDB_QueryNode& qnode = tr.GetValue(); if (qnode.GetType() != CBDB_QueryNode::eValue) { qnode.SetValue(kEmptyStr); } qnode.SetAltValue(kEmptyStr); return eTreeTraverse;}void CBDB_Query::ResetQueryClause(){ TreeDepthFirstTraverse(*m_QueryClause, s_ResetQueryNode);}void CBDB_Query::SetQueryClause(TQueryClause* query_clause){ delete m_QueryClause; m_QueryClause = query_clause;}CBDB_Query::TQueryClause* CBDB_Query::NewOperatorNode(CBDB_QueryNode::EOperatorType otype, const string& arg1, const string& arg2){ auto_ptr<TQueryClause> tr(new TQueryClause(CBDB_QueryNode(otype))); tr->AddNode(new TQueryClause(CBDB_QueryNode(arg1))); tr->AddNode(new TQueryClause(CBDB_QueryNode(arg2))); return tr.release();}CBDB_Query::TQueryClause* CBDB_Query::NewOperatorNode(CBDB_QueryNode::EOperatorType otype, TQueryClause* arg1, TQueryClause* arg2){ auto_ptr<TQueryClause> tr(new TQueryClause(CBDB_QueryNode(otype))); if (arg1) tr->AddNode(arg1); if (arg2) tr->AddNode(arg2); return tr.release();}CBDB_Query::TQueryClause* CBDB_Query::NewLogicalNode(CBDB_QueryNode::ELogicalType ltype, TQueryClause* arg1, TQueryClause* arg2){ auto_ptr<TQueryClause> tr(new TQueryClause(CBDB_QueryNode(ltype))); if (arg1) tr->AddNode(arg1); if (arg2) tr->AddNode(arg2); return tr.release();}/////////////////////////////////////////////////////////////////////////////// Internal evaluation functors///// Field resolution functor////// Every node is inspected if it contains a field value and/// marks it using CBDB_File::TUnifiedFieldIndex///class CQueryTreeFieldResolveFunc{public: CQueryTreeFieldResolveFunc(CBDB_File& db_file) : m_File(db_file) {} ETreeTraverseCode operator()(CTreeNode<CBDB_QueryNode>& tr, int delta) { CBDB_QueryNode& qnode = tr.GetValue(); if (delta == 0 || delta == 1) { // If node has children, we skip it and process on the way back if (!tr.IsLeaf()) return eTreeTraverse; } if (qnode.GetType() == CBDB_QueryNode::eDBField) return eTreeTraverse; if (qnode.HasValue()) { string& fvalue = qnode.GetValue(); int len = fvalue.length(); // if string value is in apostrophe marks: remove it if (fvalue[0] == '\'' && fvalue[len-1] == '\'') { len -= 2; if (len) { qnode.SetValue(fvalue.substr(1, len)); } else { qnode.SetValue(kEmptyStr); } } else { CBDB_File::TUnifiedFieldIndex fidx = m_File.GetFieldIdx(fvalue); if (fidx) { qnode.SetField(fidx); } } } return eTreeTraverse; }private: CBDB_File& m_File;};/// Query execition environmentclass CQueryExecEnv{public: CQueryExecEnv(CBDB_File& db_file) : m_File(db_file) {} CBDB_File& GetFile(void) { return m_File; } CResourcePool<string>& GetStrPool() { return m_StrPool; }private: CQueryExecEnv(const CQueryExecEnv& qenv); CQueryExecEnv& operator=(const CQueryExecEnv& qenv);private: CBDB_File& m_File; /// Query database file CResourcePool<string> m_StrPool; /// Pool of string variables };/// Create new matcher////// @internalstaticCBoyerMooreMatcher* s_MakeNewMatcher(const string& search_value){ CBoyerMooreMatcher* matcher = new CBoyerMooreMatcher(search_value, NStr::eNocase, CBoyerMooreMatcher::ePrefixMatch); matcher->InitCommonDelimiters(); return matcher;}/// Base class for functions of the evaluation engine////// @internalclass CScannerFunctor{public: CScannerFunctor(CQueryExecEnv& env) : m_QueryEnv(env) {}private: CScannerFunctor(const CScannerFunctor&); CScannerFunctor& operator=(const CScannerFunctor&);protected: CQueryExecEnv& m_QueryEnv;};/// Base class for N argument functions////// @internalclass CScannerFunctorArgN : public CScannerFunctor{public: /// Enum indicates how to interpret the plain value /// tree elements. It can be takes as is (eNoCheck) or /// converted to a "in any field" variant of check /// (similar to what PubMed does) enum EAllFieldsCheck { eNoCheck, eCheckAll }; /// Vector of strings borrowed from the query environment /// pool to keep temporary values during the query execution typedef vector<string*> TArgValueVector; /// Vector of arguments, elements can point on values from /// TArgValueVector or variables located in the query tree itself typedef vector<const string*> TArgVector; /// String matchers used for substring search typedef vector<CBoyerMooreMatcher*> TStringMatcherVector; /// If argument is a db field corresponding vector element /// contains the field pointer typedef vector<const CBDB_Field*> TFieldVector;public: CScannerFunctorArgN(CQueryExecEnv& env) : CScannerFunctor(env) {} ~CScannerFunctorArgN(); /// Checks if value is equal to any field in the database bool IsAnyField(CBDB_File& dbf, const string& search_value, unsigned int arg_idx) { CBoyerMooreMatcher* matcher = GetMatcher(search_value, arg_idx); CBDB_File::TUnifiedFieldIndex fidx = BDB_find_field(dbf, *matcher); return (fidx != 0); } CBoyerMooreMatcher* GetMatcher(const string& search_value, unsigned int arg_idx) { CBoyerMooreMatcher* matcher = m_MatcherVector[arg_idx]; if (!matcher) { m_MatcherVector[arg_idx] = matcher = s_MakeNewMatcher(search_value); } return matcher; } /// Extract function arguments from the parsing tree void GetArguments(CTreeNode<CBDB_QueryNode>& tr, EAllFieldsCheck check_mode = eNoCheck) { CBDB_File& db_file = m_QueryEnv.GetFile(); CResourcePool<string>& str_pool = m_QueryEnv.GetStrPool(); typedef CTreeNode<CBDB_QueryNode> TTree; TTree::TNodeList_CI it = tr.SubNodeBegin(); TTree::TNodeList_CI it_end = tr.SubNodeEnd(); for (unsigned i = 0; it != it_end; ++it, ++i) { const TTree* t = *it; const CBDB_QueryNode& qnode = t->GetValue(); ResizeVectors(i + 1); // Check if the argument should be taken from the // db field if (qnode.GetType() == CBDB_QueryNode::eDBField) { int fidx = qnode.GetFiledIdx(); const CBDB_Field& fld = db_file.GetField(fidx); SyncArgValue(i, str_pool); fld.ToString(*m_ArgValueVector[i]); m_FieldVector[i] = &fld; continue; } // field value check mode // eCheckAll is coming from logical functions if they // support "value AND anothervalue" notation // (search services work like that) if ((check_mode == eCheckAll) && (qnode.GetType() == CBDB_QueryNode::eValue)) { const string& v = qnode.GetValue(); const char* sz = "0"; if (IsAnyField(db_file, v, i)) { sz = "1"; } SyncArgValue(i, str_pool); *m_ArgValueVector[i] = sz; continue; } // Get constant value or return type of the subnodes const string& str = qnode.GetValue(); m_ArgVector[i] = &str; } // for } const string* GetArg(unsigned int idx) const { _ASSERT(idx < m_ArgVector.size()); return m_ArgVector[idx]; } const CBDB_Field* GetArgField(unsigned int idx) const { _ASSERT(idx < m_FieldVector.size()); return m_FieldVector[idx]; } void SetResult(CBDB_QueryNode& qnode, bool res) { if (res) { qnode.SetValue("1"); } else { qnode.SetValue("0"); } }private: /// Syncronously resize all arguments vectors void ResizeVectors(unsigned int new_size) { TArgVector::size_type old_size = m_ArgVector.size(); _ASSERT(new_size <= old_size + 1); // 1 increments only if (new_size > old_size) { m_ArgVector.push_back(0); m_ArgValueVector.push_back(0); m_MatcherVector.push_back(0); m_FieldVector.push_back(0); } } /// m_ArgVector[idx] = m_ArgValueVector[idx] void SyncArgValue(unsigned int idx, CResourcePool<string>& str_pool) { if (m_ArgValueVector[idx] == 0) { m_ArgValueVector[idx] = str_pool.Get(); } m_ArgVector[idx] = m_ArgValueVector[idx]; }protected: TArgVector m_ArgVector; TArgValueVector m_ArgValueVector; TStringMatcherVector m_MatcherVector; TFieldVector m_FieldVector;};CScannerFunctorArgN::~CScannerFunctorArgN(){ CResourcePool<string>& str_pool = m_QueryEnv.GetStrPool(); unsigned int size = m_ArgValueVector.size(); for (unsigned int i = 0; i < size; ++i) { string* str = m_ArgValueVector[i]; if (str) { str_pool.Return(str); } CBoyerMooreMatcher* matcher = m_MatcherVector[i]; delete matcher; }}/// EQ function ////// @internalclass CScannerFunctorEQ : public CScannerFunctorArgN{public: CScannerFunctorEQ(CQueryExecEnv& env, bool not_flag) : CScannerFunctorArgN(env), m_NotFlag(not_flag) {} bool IsNot() const { return m_NotFlag; } void Eval(CTreeNode<CBDB_QueryNode>& tr) { GetArguments(tr); CBDB_QueryNode& qnode = tr.GetValue(); const string* arg0 = GetArg(0); const string* arg1 = GetArg(1); const CBDB_Field* fld0 = GetArgField(0); const CBDB_Field* fld1 = GetArgField(1); // here we check two cases: // field = "value" // "value" == field if (fld0 != 0 && fld1 == 0) { CBoyerMooreMatcher* matcher = GetMatcher(*arg1, 0); int pos = matcher->Search(*arg0); if (pos == -1) { // not found qnode.SetValue("0"); } else { qnode.SetValue("1"); } return; } if (fld0 == 0 && fld1 != 0) { CBoyerMooreMatcher* matcher = GetMatcher(*arg0, 0); int pos = matcher->Search(*arg1); if (pos == -1) { // not found qnode.SetValue("0"); } else { qnode.SetValue("1"); } return; } // Plain equal bool res = (*arg0 == *arg1); if (IsNot()) res = !res; SetResult(qnode, res); }protected: bool m_NotFlag;};/// Basic class for all comparison (GT, LT, etc) functors////// @internalclass CScannerFunctorComp : public CScannerFunctorArgN{public: CScannerFunctorComp(CQueryExecEnv& env) : CScannerFunctorArgN(env) {} int CmpEval(CTreeNode<CBDB_QueryNode>& tr) { GetArguments(tr); const string* arg0 = GetArg(0); const string* arg1 = GetArg(1); int cmpres = arg0->compare(*arg1); return cmpres; }};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?