bdb_cursor.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:14k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: bdb_cursor.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:37:17  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: bdb_cursor.cpp,v 1000.2 2004/06/01 18:37:17 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author: Anatoliy Kuznetsov
  35.  *
  36.  * File Description:  BDB library cursor implementations.
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <bdb/bdb_cursor.hpp>
  41. #include <db.h>
  42. BEGIN_NCBI_SCOPE
  43. //////////////////////////////////////////////////////////////////
  44. //
  45. // Internal class used by CBDB_FileCursor to represent search
  46. // condition criteries.
  47. //
  48. class CBDB_FC_Condition
  49. {
  50. public:
  51.     // Get field buffer reference (non-const)
  52.     CBDB_BufferManager&       GetBuffer()       { return m_Buf; }
  53.     // Get field buffer reference (const)
  54.     const CBDB_BufferManager& GetBuffer() const { return m_Buf; }
  55.     // Get number of fields assigned to condition
  56.     unsigned int GetFieldsAssigned() const { return m_FieldsAssigned; }
  57.     // +1 increment of number of assigned fields.
  58.     // Return new fields count
  59.     unsigned int IncFieldsAssigned()
  60.     {
  61.         _ASSERT(m_Buf.FieldCount()-1 >= m_FieldsAssigned);
  62.         m_Cursor.ResetFirstFetched();
  63.         return ++m_FieldsAssigned;
  64.     }
  65.     // Return TRUE if all search criteria fileds have been assigned
  66.     bool IsComplete() const
  67.     {
  68.         return m_KeyBuf.FieldCount() == GetFieldsAssigned();
  69.     }
  70.     // Return next unassigned field
  71.     IBDB_FieldConvert& GetUnassignedField()
  72.     {
  73.         _ASSERT(m_FieldsAssigned < m_Buf.FieldCount());
  74.         return m_Cursor.GetFieldConvert(m_Buf, m_FieldsAssigned);
  75.     }
  76.     ~CBDB_FC_Condition() { DeleteFields(m_Buf); }
  77. protected:
  78.     enum EIncompleteVal
  79.     {
  80.         eAssignMinVal,
  81.         eAssignMaxVal
  82.     };
  83.     // Constructor. key_buf - key buffer of the main table
  84.     CBDB_FC_Condition(const CBDB_BufferManager& key_buf,
  85.                       CBDB_FileCursor&          cursor)
  86.         : m_KeyBuf(key_buf),
  87.           m_Cursor(cursor),
  88.           m_FieldsAssigned(0)
  89.     {
  90.         m_Buf.DuplicateStructureFrom(key_buf);
  91.         m_Buf.Construct();
  92.     }
  93.     // Set incomplete (non assigned) fields to min(max) possible values
  94.     void InitUnassignedFields(EIncompleteVal incv)
  95.     {
  96.         if (incv == eAssignMinVal) {
  97.             m_Buf.SetMinVal(m_FieldsAssigned, m_Buf.FieldCount());
  98.         } else {  // eAssignMaxVal
  99.             m_Buf.SetMaxVal(m_FieldsAssigned, m_Buf.FieldCount());
  100.         }
  101.     }
  102.     // Set number of assigned fields to zero
  103.     void ResetUnassigned()
  104.     {
  105.         m_FieldsAssigned = 0;
  106.     }
  107. private:
  108.     CBDB_FC_Condition(const CBDB_FC_Condition&);
  109.     const CBDB_FC_Condition&
  110.                operator= (const CBDB_FC_Condition&);
  111. private:
  112.     // Reference on "parent file" key buffer
  113.     const CBDB_BufferManager&   m_KeyBuf;
  114.     // Reference on parent cursor
  115.     CBDB_FileCursor&            m_Cursor;
  116.     // Field buffer. Correspond to
  117.     CBDB_BufferManager          m_Buf;
  118.     // Number of fields assigned (for multi-segment) prefix searches
  119.     unsigned int                m_FieldsAssigned;
  120.     friend class CBDB_FileCursor;
  121.     friend class CBDB_ConditionHandle;
  122. };
  123. /////////////////////////////////////////////////////////////////////////////
  124. //  CBDB_ConditionHandle::
  125. //
  126. CBDB_ConditionHandle::CBDB_ConditionHandle(CBDB_FC_Condition& cond)
  127.  : m_Condition(cond)
  128. {}
  129. CBDB_ConditionHandle::~CBDB_ConditionHandle()
  130. {
  131.     delete &m_Condition;
  132. }
  133. /////////////////////////////////////////////////////////////////////////////
  134. //  CBDB_FileCursor::
  135. //
  136. CBDB_FileCursor::CBDB_FileCursor(CBDB_File& dbf)
  137. : m_Dbf(dbf),
  138.   From( *(new CBDB_FC_Condition(*dbf.m_KeyBuf, *this))  ),
  139.   To( *(new CBDB_FC_Condition(*dbf.m_KeyBuf, *this)) ),
  140.   m_DBC(0),
  141.   m_CondFrom(eFirst),
  142.   m_CondTo(eLast),
  143.   m_FetchDirection(eForward),
  144.   m_FirstFetched(false)
  145. {
  146.     m_DBC = m_Dbf.CreateCursor();
  147. }
  148. CBDB_FileCursor::CBDB_FileCursor(CBDB_File& dbf, CBDB_Transaction& trans)
  149. : m_Dbf(dbf),
  150.   From( *(new CBDB_FC_Condition(*dbf.m_KeyBuf, *this))  ),
  151.   To( *(new CBDB_FC_Condition(*dbf.m_KeyBuf, *this)) ),
  152.   m_DBC(0),
  153.   m_CondFrom(eFirst),
  154.   m_CondTo(eLast),
  155.   m_FetchDirection(eForward),
  156.   m_FirstFetched(false)
  157. {
  158.     m_DBC = m_Dbf.CreateCursor(&trans);
  159. }
  160. CBDB_FileCursor::~CBDB_FileCursor()
  161. {
  162.     if (m_DBC) {
  163.         m_DBC->c_close(m_DBC);
  164.     }
  165. }
  166. void CBDB_FileCursor::SetCondition(ECondition cond_from, ECondition cond_to)
  167. {
  168.     m_FetchDirection = eForward;
  169.     if (cond_from == eGT  ||  cond_from == eGE) {
  170.         if (cond_to == eGT  ||  cond_to == eGE) {
  171.             cond_to = eNotSet;
  172.         }
  173.     }
  174.     else
  175.     if (cond_from == eLT  ||  cond_from == eLE) {
  176.         if (cond_to == eLT  ||  cond_to  == eLE) {
  177.             cond_to = eNotSet;
  178.         }
  179.         m_FetchDirection = eBackward;
  180.     }
  181.     else
  182.     if (cond_from == eEQ) {
  183.         if (cond_to != eNotSet)
  184.             cond_to = eNotSet;
  185.     }
  186.     else
  187.     if (cond_from == eLast) {
  188.         m_FetchDirection = eBackward;
  189.     }
  190.     else
  191.     if (cond_from == eNotSet) {
  192.         BDB_THROW(eIdxSearch, "Cursor search 'FROM' parameter must be set");
  193.     }
  194.     if (cond_to == eEQ)
  195.         BDB_THROW(eIdxSearch, "Cursor search 'TO' parameter cannot be EQ");
  196.     m_CondFrom     = cond_from;
  197.     m_CondTo       = cond_to;
  198.     m_FirstFetched = false;
  199.     From.m_Condition.ResetUnassigned();
  200.     To.m_Condition.ResetUnassigned();
  201. }
  202. EBDB_ErrCode CBDB_FileCursor::Update(CBDB_File::EAfterWrite write_flag)
  203. {
  204.     if(m_DBC == 0) 
  205.         BDB_THROW(eInvalidValue, "Try to use invalid cursor");
  206.     
  207.     return m_Dbf.WriteCursor(m_DBC, DB_CURRENT, write_flag);
  208. }
  209. EBDB_ErrCode CBDB_FileCursor::Delete(CBDB_File::EIgnoreError on_error)
  210. {
  211.     return m_Dbf.DeleteCursor(m_DBC, on_error);
  212. }
  213. CBDB_FileCursor::TRecordCount CBDB_FileCursor::KeyDupCount() const
  214. {
  215.     if(m_DBC == 0) 
  216.         BDB_THROW(eInvalidValue, "Try to use invalid cursor");
  217.     db_recno_t ret;
  218.     
  219.     if( int err = m_DBC->c_count(m_DBC, &ret, 0) )
  220.         BDB_ERRNO_THROW(err, "Failed to count duplicate entries for cursor");
  221.     
  222.     return TRecordCount(ret);
  223. }
  224. EBDB_ErrCode CBDB_FileCursor::FetchFirst()
  225. {
  226.     m_FirstFetched = true;
  227.     ECondition cond_from = m_CondFrom;
  228.     if (m_CondFrom != eFirst && m_CondFrom != eLast) {
  229.         // If cursor from buffer contains not all key fields
  230.         // (prefix search) we set all remaining fields to max.
  231.         // possible value for GT condition
  232.         From.m_Condition.InitUnassignedFields(m_CondFrom == eGT ?
  233.                                      CBDB_FC_Condition::eAssignMaxVal
  234.                                      :
  235.                                      CBDB_FC_Condition::eAssignMinVal);
  236.         m_Dbf.m_KeyBuf->CopyFieldsFrom(From.m_Condition.GetBuffer());
  237.         To.m_Condition.InitUnassignedFields(m_CondTo == eLE ?
  238.                                    CBDB_FC_Condition::eAssignMaxVal
  239.                                    :
  240.                                    CBDB_FC_Condition::eAssignMinVal);
  241.         // Incomplete == search transformed into >= search with incomplete
  242.         // fields set to min
  243.         if (m_CondFrom == eEQ  &&  !From.m_Condition.IsComplete()) {
  244.             cond_from = eGE;
  245.         }
  246.     }
  247.     unsigned int flag;
  248.     switch ( cond_from ) {
  249.         case eFirst:
  250.             flag = DB_FIRST;       // first record retrieval
  251.             break;
  252.         case eLast:                // last record
  253.             flag = DB_LAST;
  254.             break;
  255.         case eEQ:
  256.             flag = DB_SET;         // precise shot
  257.             break;
  258.         case eGT:
  259.         case eGE:
  260.         case eLT:
  261.         case eLE:
  262.             flag = DB_SET_RANGE;   // permits partial key and range searches
  263.             break;
  264.         default:
  265.             BDB_THROW(eIdxSearch, "Invalid FROM condition type");
  266.     }
  267.     EBDB_ErrCode ret = m_Dbf.ReadCursor(m_DBC, flag);
  268.     if (ret != eBDB_Ok)
  269.         return ret;
  270.     // Berkeley DB does not support "<" ">" conditions, so we need to scroll
  271.     // up or down to reach the interval criteria.
  272.     if (m_CondFrom == eGT) {
  273.         while (m_Dbf.m_KeyBuf->Compare(From.m_Condition.m_Buf) == 0) {
  274.             ret = m_Dbf.ReadCursor(m_DBC, DB_NEXT);
  275.             if (ret != eBDB_Ok)
  276.                 return ret;
  277.         }
  278.     }
  279.     else
  280.     if (m_CondFrom == eLT) {
  281.         while (m_Dbf.m_KeyBuf->Compare(From.m_Condition.m_Buf) == 0) {
  282.             ret = m_Dbf.ReadCursor(m_DBC, DB_PREV);
  283.             if (ret != eBDB_Ok)
  284.                 return ret;
  285.         }
  286.     }
  287.     else
  288.     if (m_CondFrom == eEQ && !From.m_Condition.IsComplete()) {
  289.         int cmp =
  290.             m_Dbf.m_KeyBuf->Compare(From.m_Condition.GetBuffer(),
  291.                                     From.m_Condition.GetFieldsAssigned());
  292.         if (cmp != 0) {
  293.             return eBDB_NotFound;
  294.         }
  295.     }
  296.     if ( !TestTo() ) {
  297.         ret = eBDB_NotFound;
  298.     }
  299.     return ret;
  300. }
  301. EBDB_ErrCode CBDB_FileCursor::Fetch(EFetchDirection fdir)
  302. {
  303.     if ( !m_FirstFetched )
  304.         return FetchFirst();
  305.     if (fdir == eDefault)
  306.         fdir = m_FetchDirection;
  307.     unsigned int flag = (fdir == eForward) ? DB_NEXT : DB_PREV;
  308.     EBDB_ErrCode ret;
  309.     while (1) {
  310.         ret = m_Dbf.ReadCursor(m_DBC, flag);
  311.         if (ret != eBDB_Ok) {
  312.             ret = eBDB_NotFound;
  313.             break;
  314.         }
  315.         if ( !TestTo() ) {
  316.             ret = eBDB_NotFound;
  317.             break;
  318.         }
  319.         // Check if we have fallen out of the FROM range
  320.         if (m_CondFrom == eEQ) {
  321.             int cmp =
  322.                 m_Dbf.m_KeyBuf->Compare(From.m_Condition.GetBuffer(),
  323.                                         From.m_Condition.GetFieldsAssigned());
  324.             if (cmp != 0) {
  325.                 ret = eBDB_NotFound;
  326.             }
  327.         }
  328.         break;
  329.     } // while
  330.     if (ret != eBDB_Ok)
  331.     {
  332.         From.m_Condition.ResetUnassigned();
  333.         To.m_Condition.ResetUnassigned();
  334.     }
  335.     return ret;
  336. }
  337. bool CBDB_FileCursor::TestTo() const
  338. {
  339.     switch (m_CondTo) {
  340.         case eEQ:
  341.             return (m_Dbf.m_KeyBuf->Compare(To.m_Condition.GetBuffer()) == 0);
  342.         case eGT:
  343.             return (m_Dbf.m_KeyBuf->Compare(To.m_Condition.GetBuffer()) >  0);
  344.         case eGE:
  345.             return (m_Dbf.m_KeyBuf->Compare(To.m_Condition.GetBuffer()) >= 0);
  346.         case eLT:
  347.             return (m_Dbf.m_KeyBuf->Compare(To.m_Condition.GetBuffer())  < 0);
  348.         case eLE:
  349.             return (m_Dbf.m_KeyBuf->Compare(To.m_Condition.GetBuffer()) <= 0);
  350.         default:
  351.             break;
  352.     }
  353.     return true;
  354. }
  355. /////////////////////////////////////////////////////////////////////////////
  356. //
  357. //  Operators
  358. //
  359. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (int val)
  360. {
  361.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  362.     cnv.SetInt(val);
  363.     m_Condition.IncFieldsAssigned();
  364.     return *this;
  365. }
  366. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (unsigned int val)
  367. {
  368.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  369.     cnv.SetUint(val);
  370.     m_Condition.IncFieldsAssigned();
  371.     return *this;
  372. }
  373. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (float val)
  374. {
  375.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  376.     cnv.SetFloat(val);
  377.     m_Condition.IncFieldsAssigned();
  378.     return *this;
  379. }
  380. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (double val)
  381. {
  382.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  383.     cnv.SetDouble(val);
  384.     m_Condition.IncFieldsAssigned();
  385.     return *this;
  386. }
  387. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (const char* val)
  388. {
  389.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  390.     cnv.SetString(val);
  391.     m_Condition.IncFieldsAssigned();
  392.     return *this;
  393. }
  394. CBDB_ConditionHandle& CBDB_ConditionHandle::operator<< (const string& val)
  395. {
  396.     IBDB_FieldConvert& cnv = m_Condition.GetUnassignedField();
  397.     cnv.SetString(val.c_str());
  398.     m_Condition.IncFieldsAssigned();
  399.     return *this;
  400. }
  401. END_NCBI_SCOPE
  402. /*
  403.  * ===========================================================================
  404.  * $Log: bdb_cursor.cpp,v $
  405.  * Revision 1000.2  2004/06/01 18:37:17  gouriano
  406.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13
  407.  *
  408.  * Revision 1.13  2004/05/17 20:55:11  gorelenk
  409.  * Added include of PCH ncbi_pch.hpp
  410.  *
  411.  * Revision 1.12  2004/05/06 19:19:22  rotmistr
  412.  * Cursor KeyDupCount added
  413.  *
  414.  * Revision 1.11  2004/05/06 18:18:14  rotmistr
  415.  * Cursor Update/Delete implemented
  416.  *
  417.  * Revision 1.10  2004/02/17 19:05:21  kuznets
  418.  * GCC warnings fix
  419.  *
  420.  * Revision 1.9  2003/12/29 13:23:53  kuznets
  421.  * Added support for transaction protected cursors.
  422.  *
  423.  * Revision 1.8  2003/12/29 12:54:33  kuznets
  424.  * Fixed cursor leak.
  425.  *
  426.  * Revision 1.7  2003/07/21 19:51:04  kuznets
  427.  * Performance tweak: do not worry about incomplete key fields when
  428.  * "give me all records" cursor was requested
  429.  *
  430.  * Revision 1.6  2003/07/02 17:55:35  kuznets
  431.  * Implementation modifications to eliminated direct dependency from <db.h>
  432.  *
  433.  * Revision 1.5  2003/05/01 13:42:12  kuznets
  434.  * Bug fix
  435.  *
  436.  * Revision 1.4  2003/04/30 20:25:42  kuznets
  437.  * Bug fix
  438.  *
  439.  * Revision 1.3  2003/04/29 19:07:22  kuznets
  440.  * Cosmetics..
  441.  *
  442.  * Revision 1.2  2003/04/28 14:51:55  kuznets
  443.  * #include directives changed to conform the NCBI policy
  444.  *
  445.  * Revision 1.1  2003/04/24 16:34:30  kuznets
  446.  * Initial revision
  447.  *
  448.  * ===========================================================================
  449.  */