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 + -
显示快捷键?