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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: conn_impl.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:18:16  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.29
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: conn_impl.cpp,v 1000.4 2004/06/01 19:18:16 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. * File Name:  $Id: conn_impl.cpp,v 1000.4 2004/06/01 19:18:16 gouriano Exp $
  35. *
  36. * Author:  Michael Kholodov
  37. *
  38. * File Description:   Connection implementation
  39. *
  40. *
  41. * $Log: conn_impl.cpp,v $
  42. * Revision 1000.4  2004/06/01 19:18:16  gouriano
  43. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.29
  44. *
  45. * Revision 1.29  2004/05/17 21:10:28  gorelenk
  46. * Added include of PCH ncbi_pch.hpp
  47. *
  48. * Revision 1.28  2004/04/26 14:16:56  kholodov
  49. * Modified: recreate the command objects each time the Get...() is called
  50. *
  51. * Revision 1.27  2004/04/12 14:25:33  kholodov
  52. * Modified: resultset caching scheme, fixed single connection handling
  53. *
  54. * Revision 1.26  2004/04/08 15:56:58  kholodov
  55. * Multiple bug fixes and optimizations
  56. *
  57. * Revision 1.25  2004/03/12 16:27:09  sponomar
  58. * correct nested querys
  59. *
  60. * Revision 1.23  2004/03/08 22:15:19  kholodov
  61. * Added: 3 new Get...() methods internally
  62. *
  63. * Revision 1.22  2004/02/27 14:37:33  kholodov
  64. * Modified: set collection replaced by list for listeners
  65. *
  66. * Revision 1.21  2003/11/18 17:00:01  kholodov
  67. * Added: CloneConnection() method
  68. *
  69. * Revision 1.20  2003/03/07 21:21:15  kholodov
  70. * Added: IsAlive() method
  71. *
  72. * Revision 1.19  2003/01/09 16:10:17  sapojnik
  73. * CConnection::Connect -- do not attempt SetDbName() if connection failed
  74. *
  75. * Revision 1.18  2002/11/27 17:19:49  kholodov
  76. * Added: Error output redirection to CToMultiExHandler object.
  77. *
  78. * Revision 1.17  2002/10/03 18:50:00  kholodov
  79. * Added: additional TRACE diagnostics about object deletion
  80. * Fixed: setting parameters in IStatement object is fully supported
  81. * Added: IStatement::ExecuteLast() to execute the last statement with
  82. * different parameters if any
  83. *
  84. * Revision 1.16  2002/09/30 20:45:34  kholodov
  85. * Added: ForceSingle() method to enforce single connection used
  86. *
  87. * Revision 1.15  2002/09/23 18:25:10  kholodov
  88. * Added: GetDataSource() method.
  89. *
  90. * Revision 1.14  2002/09/18 18:49:27  kholodov
  91. * Modified: class declaration and Action method to reflect
  92. * direct inheritance of CActiveObject from IEventListener
  93. *
  94. * Revision 1.13  2002/09/16 19:34:40  kholodov
  95. * Added: bulk insert support
  96. *
  97. * Revision 1.12  2002/09/09 20:48:56  kholodov
  98. * Added: Additional trace output about object life cycle
  99. * Added: CStatement::Failed() method to check command status
  100. *
  101. * Revision 1.11  2002/06/24 19:10:03  kholodov
  102. * Added more trace diagnostics
  103. *
  104. * Revision 1.10  2002/06/24 18:06:49  kholodov
  105. * Added more detailed diagnostics on connections
  106. *
  107. * Revision 1.9  2002/06/21 14:42:31  kholodov
  108. * Added: reporting connection deletions in debug mode
  109. *
  110. * Revision 1.8  2002/05/16 22:11:11  kholodov
  111. * Improved: using minimum connections possible
  112. *
  113. * Revision 1.7  2002/04/15 19:08:55  kholodov
  114. * Changed GetContext() -> GetDriverContext
  115. *
  116. * Revision 1.6  2002/02/08 22:43:10  kholodov
  117. * Set/GetDataBase() renamed to Set/GetDatabase() respectively
  118. *
  119. * Revision 1.5  2002/02/08 21:29:54  kholodov
  120. * SetDataBase() restored, connection cloning algorithm changed
  121. *
  122. * Revision 1.4  2002/02/08 17:47:34  kholodov
  123. * Removed SetDataBase() method
  124. *
  125. * Revision 1.3  2002/02/08 17:38:26  kholodov
  126. * Moved listener registration to parent objects
  127. *
  128. * Revision 1.2  2002/02/06 22:20:09  kholodov
  129. * Connections are cloned for CallableStatement and Cursor
  130. *
  131. * Revision 1.1  2002/01/30 14:51:21  kholodov
  132. * User DBAPI implementation, first commit
  133. *
  134. *
  135. *
  136. *
  137. */
  138. #include <ncbi_pch.hpp>
  139. #include <dbapi/driver/public.hpp>
  140. //#include <dbapi/driver/interfaces.hpp>
  141. //#include <dbapi/driver/exception.hpp>
  142. #include "conn_impl.hpp"
  143. #include "ds_impl.hpp"
  144. #include "stmt_impl.hpp"
  145. #include "cstmt_impl.hpp"
  146. #include "cursor_impl.hpp"
  147. #include "bulkinsert.hpp"
  148. #include "err_handler.hpp"
  149. BEGIN_NCBI_SCOPE
  150. // Implementation
  151. CConnection::CConnection(CDataSource* ds)
  152.     : m_ds(ds), m_connection(0), m_connCounter(1), m_connUsed(false),
  153.       m_modeMask(0), m_forceSingle(false), m_multiExH(0),
  154.       m_stmt(0), m_cstmt(0), m_cursor(0), m_bulkInsert(0)
  155. {
  156.     _TRACE("Default connection " << (void *)this << " created...");
  157.     SetIdent("CConnection");
  158. }
  159. CConnection::CConnection(CDB_Connection *conn, CDataSource* ds)
  160.     : m_ds(ds), m_connection(conn), m_connCounter(-1), m_connUsed(false),
  161.       m_modeMask(0), m_forceSingle(false), m_multiExH(0),
  162.       m_stmt(0), m_cstmt(0), m_cursor(0), m_bulkInsert(0)
  163. {
  164.     _TRACE("Auxiliary connection " << (void *)this << " created...");
  165.     SetIdent("CConnection");
  166. }
  167. void CConnection::SetMode(EConnMode mode)
  168. {
  169.     m_modeMask |= mode;
  170. }
  171. void CConnection::ResetMode(EConnMode mode)
  172. {
  173.     m_modeMask &= ~mode;
  174. }
  175. IDataSource* CConnection::GetDataSource()
  176. {
  177.     return m_ds;
  178. }
  179. unsigned int CConnection::GetModeMask()
  180. {
  181.     return m_modeMask;
  182. }
  183. void CConnection::ForceSingle(bool enable)
  184. {
  185.     m_forceSingle = enable;
  186. }
  187. void CConnection::Connect(const string& user,
  188.                           const string& password,
  189.                           const string& server,
  190.                           const string& database)
  191. {
  192.     m_connection = m_ds->
  193.         GetDriverContext()->Connect(server,
  194.                                     user,
  195.                                     password,
  196.                                     m_modeMask,
  197.                                     m_ds->IsPoolUsed());
  198.     if(m_connection) {
  199.         SetDbName(database);
  200.     }
  201. }
  202. CConnection::~CConnection()
  203. {
  204.     if( IsAux() ) {
  205.         _TRACE("Auxiliary connection " << (void*)this << " is being deleted...");
  206.     } else {
  207.         _TRACE("Default connection " << (void*)this << " is being deleted...");
  208.     }
  209.     FreeResources();
  210.     Notify(CDbapiDeletedEvent(this));
  211.     _TRACE(GetIdent() << " " << (void*)this << " deleted.");
  212. }
  213. void CConnection::SetDatabase(const string& name)
  214. {
  215.   SetDbName(name);
  216. }
  217. string CConnection::GetDatabase()
  218. {
  219.     return m_database;
  220. }
  221. bool CConnection::IsAlive()
  222. {
  223.     if( m_connection != 0 )
  224.         return m_connection->IsAlive();
  225.     else
  226.         return false;
  227. }
  228. void CConnection::SetDbName(const string& name,
  229.                             CDB_Connection* conn)
  230. {
  231.     m_database = name;
  232.     if( m_database.empty() )
  233.         return;
  234.     CDB_Connection* work = (conn == 0 ? m_connection : conn);
  235.     string sql = "use " + m_database;
  236.     CDB_LangCmd* cmd = work->LangCmd(sql.c_str());
  237.     cmd->Send();
  238.     while( cmd->HasMoreResults() ) {
  239.         cmd->Result();
  240.     }
  241.     delete cmd;
  242. }
  243. CDB_Connection* CConnection::CloneCDB_Conn()
  244. {
  245.     CDB_Connection *temp = m_ds->
  246.    GetDriverContext()->Connect(GetCDB_Connection()->ServerName(),
  247.                                GetCDB_Connection()->UserName(),
  248.                                GetCDB_Connection()->Password(),
  249.                                m_modeMask,
  250.                                true);
  251.     _TRACE("CDB_Connection cloned");
  252.     SetDbName(m_database, temp);
  253.     return temp;
  254. }
  255. void CConnection::Close()
  256. {
  257.     FreeResources();
  258. }
  259. void CConnection::FreeResources() 
  260. {
  261.     delete m_stmt;
  262.     //m_stmt = 0;
  263.     delete m_cstmt;
  264.     //m_cstmt = 0;
  265.     delete m_cursor;
  266.     // m_cursor = 0;
  267.     delete m_bulkInsert;
  268.     //m_bulkInsert = 0;
  269.     delete m_connection;
  270.     m_connection = 0;
  271. }
  272. CConnection* CConnection::Clone()
  273. {
  274.     CConnection *conn = new CConnection(CloneCDB_Conn(), m_ds);
  275.     //conn->AddListener(m_ds);
  276.     //m_ds->AddListener(conn);
  277.     conn->SetDbName(GetDatabase());
  278.     ++m_connCounter;
  279.     return conn;
  280. }
  281. IConnection* CConnection::CloneConnection()
  282. {
  283.     CConnection *conn = new CConnection(m_ds);
  284.     conn->m_modeMask = this->m_modeMask;
  285.     conn->m_forceSingle = this->m_forceSingle;
  286.     conn->m_connection = CloneCDB_Conn();
  287.     conn->m_database = this->m_database;
  288.     conn->AddListener(m_ds);
  289.     m_ds->AddListener(conn);
  290.     return conn;
  291. }
  292. // New part
  293. IStatement* CConnection::GetStatement()
  294. {
  295.     if( m_connUsed ) 
  296.         throw CDbapiException("CConnection::GetStatement(): Connection taken, cannot use this method");
  297.     if( m_stmt == 0 ) {
  298.         m_stmt = new CStatement(this);
  299.         AddListener(m_stmt);
  300.         m_stmt->AddListener(this);
  301.     }
  302.     return m_stmt;
  303. }
  304. ICallableStatement*
  305. CConnection::GetCallableStatement(const string& proc,
  306.                                   int nofArgs)
  307. {
  308.     if( m_connUsed ) 
  309.         throw CDbapiException("CConnection::GetCallableStatement(): Connection taken, cannot use this method");
  310.     if( m_cstmt != 0 ) {
  311.         //m_cstmt->PurgeResults();
  312.         delete m_cstmt;
  313.     }
  314.     m_cstmt = new CCallableStatement(proc, nofArgs, this);
  315.     AddListener(m_cstmt);
  316.     m_cstmt->AddListener(this);
  317.     return m_cstmt;
  318. }
  319. ICursor* CConnection::GetCursor(const string& name,
  320.                                 const string& sql,
  321.                                 int nofArgs,
  322.                                 int batchSize)
  323. {
  324.     if( m_connUsed ) 
  325.         throw CDbapiException("CConnection::GetCursor(): Connection taken, cannot use this method");
  326.     if( m_cursor != 0 ) {
  327.         delete m_cursor;
  328.     }
  329.     m_cursor = new CCursor(name, sql, nofArgs, batchSize, this);
  330.     AddListener(m_cursor);
  331.     m_cursor->AddListener(this);
  332.     return m_cursor;
  333. }
  334. IBulkInsert* CConnection::GetBulkInsert(const string& table_name,
  335.                                         unsigned int nof_cols)
  336. {
  337.     if( m_connUsed ) 
  338.         throw CDbapiException("CConnection::GetBulkInsert(): Connection taken, cannot use this method");
  339.     if( m_bulkInsert != 0 ) {
  340.         delete m_bulkInsert;
  341.     }
  342.     m_bulkInsert = new CBulkInsert(table_name, nof_cols, this);
  343.     AddListener(m_bulkInsert);
  344.     m_bulkInsert->AddListener(this);
  345.     return m_bulkInsert;
  346. }
  347. // New part end
  348. IStatement* CConnection::CreateStatement()
  349. {
  350.     if( m_stmt != 0 || m_cstmt != 0 || m_cursor != 0 || m_bulkInsert != 0 ) 
  351.         throw CDbapiException("CConnection::CreateStatement(): Get...() methods used");
  352.     
  353.     CStatement *stmt = new CStatement(GetAuxConn());
  354.     AddListener(stmt);
  355.     stmt->AddListener(this);
  356.     return stmt;
  357. }
  358. ICallableStatement*
  359. CConnection::PrepareCall(const string& proc,
  360.                          int nofArgs)
  361. {
  362.     if( m_stmt != 0 || m_cstmt != 0 || m_cursor != 0 || m_bulkInsert != 0 ) 
  363.         throw CDbapiException("CConnection::CreateCallableStatement(): Get...() methods used");
  364.     
  365.     CCallableStatement *cstmt = new CCallableStatement(proc, nofArgs, GetAuxConn());
  366.     AddListener(cstmt);
  367.     cstmt->AddListener(this);
  368.     return cstmt;
  369. }
  370. ICursor* CConnection::CreateCursor(const string& name,
  371.                                    const string& sql,
  372.                                    int nofArgs,
  373.                                    int batchSize)
  374. {
  375.     if( m_stmt != 0 || m_cstmt != 0 || m_cursor != 0 || m_bulkInsert != 0 ) 
  376.         throw CDbapiException("CConnection::CreateCursor(): Get...() methods used");
  377.     
  378.     CCursor *cur = new CCursor(name, sql, nofArgs, batchSize, GetAuxConn());
  379.     AddListener(cur);
  380.     cur->AddListener(this);
  381.     return cur;
  382. }
  383. IBulkInsert* CConnection::CreateBulkInsert(const string& table_name,
  384.                                            unsigned int nof_cols)
  385. {
  386.     if( m_stmt != 0 || m_cstmt != 0 || m_cursor != 0 || m_bulkInsert != 0 ) 
  387.         throw CDbapiException("CConnection::CreateBulkInsert(): Get...() methods used");
  388.     
  389.     CBulkInsert *bcp = new CBulkInsert(table_name, nof_cols, GetAuxConn());
  390.     AddListener(bcp);
  391.     bcp->AddListener(this);
  392.     return bcp;
  393. }
  394. void CConnection::Action(const CDbapiEvent& e)
  395. {
  396.     _TRACE(GetIdent() << " " << (void*)this << ": '" << e.GetName()
  397.            << "' received from " << e.GetSource()->GetIdent());
  398.     if(dynamic_cast<const CDbapiClosedEvent*>(&e) != 0 ) {
  399.         CStatement *stmt;
  400.         CCallableStatement *cstmt;
  401.         CCursor *cursor;
  402.         CBulkInsert *bulkInsert;
  403.         if( (cstmt = dynamic_cast<CCallableStatement*>(e.GetSource())) != 0 ) {
  404.             if( cstmt == m_cstmt ) {
  405.                 _TRACE("CConnection: Clearing cached callable statement " << (void*)m_cstmt); 
  406.                 m_cstmt = 0;
  407.             }
  408.         }
  409.         else if( (stmt = dynamic_cast<CStatement*>(e.GetSource())) != 0 ) {
  410.             if( stmt == m_stmt ) {
  411.                 _TRACE("CConnection: Clearing cached statement " << (void*)m_stmt); 
  412.                 m_stmt = 0;
  413.             }
  414.         }
  415.         else if( (cursor = dynamic_cast<CCursor*>(e.GetSource())) != 0 ) {
  416.             if( cursor == m_cursor ) {
  417.                 _TRACE("CConnection: Clearing cached cursor " << (void*)m_cursor); 
  418.                 m_cursor = 0;
  419.             }
  420.         }
  421.         else if( (bulkInsert = dynamic_cast<CBulkInsert*>(e.GetSource())) != 0 ) {
  422.             if( bulkInsert == m_bulkInsert ) {
  423.                 _TRACE("CConnection: Clearing cached bulkinsert " << (void*)m_bulkInsert); 
  424.                 m_bulkInsert = 0;
  425.             }
  426.         }
  427.         if( m_connCounter == 1 )
  428.             m_connUsed = false;
  429.     }
  430.     else if(dynamic_cast<const CDbapiAuxDeletedEvent*>(&e) != 0 ) {
  431.         if( m_connCounter > 1 ) {
  432.             --m_connCounter;
  433.             _TRACE("Server: " << GetCDB_Connection()->ServerName()
  434.                    <<", connections left: " << m_connCounter);
  435.         }
  436.         else
  437.             m_connUsed = false;
  438.     }
  439.     else if(dynamic_cast<const CDbapiDeletedEvent*>(&e) != 0 ) {
  440.         RemoveListener(e.GetSource());
  441.         if(dynamic_cast<CDataSource*>(e.GetSource()) != 0 ) {
  442.             delete this;
  443.         }
  444.     }
  445. }
  446. CConnection* CConnection::GetAuxConn()
  447. {
  448.     if( m_connCounter < 0 )
  449.         return 0;
  450.     CConnection *conn = this;
  451.     if( m_connUsed && m_forceSingle ) {
  452.         throw CDbapiException("GetAuxConn(): Extra connections not permitted");
  453.     }
  454.     if( m_connUsed ) {
  455.         conn = Clone();
  456.         _TRACE("GetAuxConn(): Server: " << GetCDB_Connection()->ServerName()
  457.                << ", open aux connection, total: " << m_connCounter);
  458.     }
  459.     else {
  460.         m_connUsed = true;
  461.         _TRACE("GetAuxconn(): server: " << GetCDB_Connection()->ServerName()
  462.                << ", no aux connections necessary, using default...");
  463.     }
  464.     return conn;
  465. }
  466. void CConnection::MsgToEx(bool v)
  467. {
  468.     if( !v ) {
  469.         // Clear the previous handlers if present
  470.         GetCDB_Connection()->PopMsgHandler(GetHandler());
  471.     }
  472.     else {
  473.         GetCDB_Connection()->PushMsgHandler(GetHandler());
  474.     }
  475. }
  476. CToMultiExHandler* CConnection::GetHandler()
  477. {
  478.     if(m_multiExH == 0 ) {
  479.         m_multiExH = new CToMultiExHandler;
  480.     }
  481.     return m_multiExH;
  482. }
  483. CDB_MultiEx* CConnection::GetErrorAsEx()
  484. {
  485.     return GetHandler()->GetMultiEx();
  486. }
  487. string CConnection::GetErrorInfo()
  488. {
  489.     CNcbiOstrstream out;
  490.     CDB_UserHandler_Stream h(&out);
  491.     h.HandleIt(GetHandler()->GetMultiEx());
  492.     return CNcbiOstrstreamToString(out);
  493. }
  494. /*
  495. void CConnection::DeleteConn(CConnection* conn)
  496. {
  497.     if( m_connCounter > 1) {
  498.         delete conn;
  499.         --m_connCounter;
  500.     }
  501.     _TRACE("Connection deleted, total left: " << m_connCounter);
  502.     return;
  503. }
  504. */
  505. END_NCBI_SCOPE