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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: connection.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:20:09  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.10
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: connection.cpp,v 1000.1 2004/06/01 19:20:09 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:  Vladimir Soussov
  35.  *
  36.  * File Description:  DBLib connection
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #ifndef USE_MS_DBLIB
  41. #  include <dbapi/driver/dblib/interfaces.hpp>
  42. #  include <dbapi/driver/dblib/interfaces_p.hpp>
  43. #else
  44. #  include <dbapi/driver/msdblib/interfaces.hpp>
  45. #  include <dbapi/driver/msdblib/interfaces_p.hpp>
  46. #endif
  47. #include <string.h>
  48. BEGIN_NCBI_SCOPE
  49. CDBL_Connection::CDBL_Connection(CDBLibContext* cntx, DBPROCESS* con,
  50.                                  bool reusable, const string& pool_name) :
  51.     m_Link(con), m_Context(cntx), m_Pool(pool_name), m_Reusable(reusable),
  52.     m_BCPAble(false), m_SecureLogin(false), m_ResProc(0)
  53. {
  54.     dbsetuserdata(m_Link, (BYTE*) this);
  55. }
  56. bool CDBL_Connection::IsAlive()
  57. {
  58.     return DBDEAD(m_Link) == FALSE;
  59. }
  60. CDB_LangCmd* CDBL_Connection::LangCmd(const string& lang_query,
  61.                                       unsigned int nof_parms)
  62. {
  63.     CDBL_LangCmd* lcmd = new CDBL_LangCmd(this, m_Link, lang_query, nof_parms);
  64.     m_CMDs.Add(lcmd);
  65.     return Create_LangCmd(*lcmd);
  66. }
  67. CDB_RPCCmd* CDBL_Connection::RPC(const string& rpc_name, unsigned int nof_args)
  68. {
  69.     CDBL_RPCCmd* rcmd = new CDBL_RPCCmd(this, m_Link, rpc_name, nof_args);
  70.     m_CMDs.Add(rcmd);
  71.     return Create_RPCCmd(*rcmd);
  72. }
  73. CDB_BCPInCmd* CDBL_Connection::BCPIn(const string& tab_name,
  74.                                      unsigned int nof_cols)
  75. {
  76.     if (!m_BCPAble) {
  77.         throw CDB_ClientEx(eDB_Error, 210003, "CDBL_Connection::BCPIn",
  78.                            "No bcp on this connection");
  79.     }
  80.     CDBL_BCPInCmd* bcmd = new CDBL_BCPInCmd(this, m_Link, tab_name, nof_cols);
  81.     m_CMDs.Add(bcmd);
  82.     return Create_BCPInCmd(*bcmd);
  83. }
  84. CDB_CursorCmd* CDBL_Connection::Cursor(const string& cursor_name,
  85.                                        const string& query,
  86.                                        unsigned int nof_params,
  87.                                        unsigned int)
  88. {
  89.     CDBL_CursorCmd* ccmd = new CDBL_CursorCmd(this, m_Link, cursor_name,
  90.                                               query, nof_params);
  91.     m_CMDs.Add(ccmd);
  92.     return Create_CursorCmd(*ccmd);
  93. }
  94. CDB_SendDataCmd* CDBL_Connection::SendDataCmd(I_ITDescriptor& descr_in,
  95.                                               size_t data_size, bool log_it)
  96. {
  97.     if (data_size < 1) {
  98.         throw CDB_ClientEx(eDB_Fatal, 210092,
  99.                            "CDBL_Connection::SendDataCmd",
  100.                            "wrong (zero) data size");
  101.     }
  102.     I_ITDescriptor* p_desc= 0;
  103.     // check what type of descriptor we've got
  104.     if(descr_in.DescriptorType() != 
  105. #ifndef MS_DBLIB_IN_USE
  106. CDBL_ITDESCRIPTOR_TYPE_MAGNUM
  107. #else
  108. CMSDBL_ITDESCRIPTOR_TYPE_MAGNUM
  109. #endif
  110. ) {
  111. // this is not a native descriptor
  112. p_desc= x_GetNativeITDescriptor(dynamic_cast<CDB_ITDescriptor&> (descr_in));
  113. if(p_desc == 0) return false;
  114.     }
  115.     
  116.     C_ITDescriptorGuard d_guard(p_desc);
  117.     CDBL_ITDescriptor& desc = p_desc? dynamic_cast<CDBL_ITDescriptor&> (*p_desc) : 
  118. dynamic_cast<CDBL_ITDescriptor&> (descr_in);
  119.     if (dbwritetext(m_Link,
  120.                     (char*) desc.m_ObjName.c_str(),
  121.                     desc.m_TxtPtr_is_NULL ? 0 : desc.m_TxtPtr,
  122.                     DBTXPLEN,
  123.                     desc.m_TimeStamp_is_NULL ? 0 : desc.m_TimeStamp,
  124.                     log_it ? TRUE : FALSE,
  125.                     (DBINT) data_size, 0) != SUCCEED ||
  126.         dbsqlok(m_Link) != SUCCEED ||
  127.         //        dbresults(m_Link) == FAIL) {
  128.         x_Results(m_Link) == FAIL) {
  129.         throw CDB_ClientEx(eDB_Error, 210093, "CDBL_Connection::SendDataCmd",
  130.                            "dbwritetext/dbsqlok/dbresults failed");
  131.     }
  132.     CDBL_SendDataCmd* sd_cmd = new CDBL_SendDataCmd(this, m_Link, data_size);
  133.     m_CMDs.Add(sd_cmd);
  134.     return Create_SendDataCmd(*sd_cmd);
  135. }
  136. bool CDBL_Connection::SendData(I_ITDescriptor& desc,
  137.                                CDB_Image& img, bool log_it){
  138.     return x_SendData(desc, dynamic_cast<CDB_Stream&> (img), log_it);
  139. }
  140. bool CDBL_Connection::SendData(I_ITDescriptor& desc,
  141.                                CDB_Text&  txt, bool log_it) {
  142.     return x_SendData(desc, dynamic_cast<CDB_Stream&> (txt), log_it);
  143. }
  144. bool CDBL_Connection::Refresh()
  145. {
  146.     // close all commands first
  147.     while (m_CMDs.NofItems()) {
  148.         CDB_BaseEnt* pCmd = static_cast<CDB_BaseEnt*> (m_CMDs.Get(0));
  149.         delete pCmd;
  150.         m_CMDs.Remove((int) 0);
  151.     }
  152.     // cancel all pending commands
  153.     if (dbcancel(m_Link) != CS_SUCCEED)
  154.         return false;
  155.     // check the connection status
  156.     return DBDEAD(m_Link) == FALSE;
  157. }
  158. const string& CDBL_Connection::ServerName() const
  159. {
  160.     return m_Server;
  161. }
  162. const string& CDBL_Connection::UserName() const
  163. {
  164.     return m_User;
  165. }
  166. const string& CDBL_Connection::Password() const
  167. {
  168.     return m_Passwd;
  169. }
  170. I_DriverContext::TConnectionMode CDBL_Connection::ConnectMode() const
  171. {
  172.     I_DriverContext::TConnectionMode mode = 0;
  173.     if ( m_BCPAble ) {
  174.         mode |= I_DriverContext::fBcpIn;
  175.     }
  176.     if ( m_SecureLogin ) {
  177.         mode |= I_DriverContext::fPasswordEncrypted;
  178.     }
  179.     return mode;
  180. }
  181. bool CDBL_Connection::IsReusable() const
  182. {
  183.     return m_Reusable;
  184. }
  185. const string& CDBL_Connection::PoolName() const
  186. {
  187.     return m_Pool;
  188. }
  189. I_DriverContext* CDBL_Connection::Context() const
  190. {
  191.     return const_cast<CDBLibContext*> (m_Context);
  192. }
  193. void CDBL_Connection::PushMsgHandler(CDB_UserHandler* h)
  194. {
  195.     m_MsgHandlers.Push(h);
  196. }
  197. void CDBL_Connection::PopMsgHandler(CDB_UserHandler* h)
  198. {
  199.     m_MsgHandlers.Pop(h);
  200. }
  201. CDB_ResultProcessor* CDBL_Connection::SetResultProcessor(CDB_ResultProcessor* rp)
  202. {
  203.     CDB_ResultProcessor* r= m_ResProc;
  204.     m_ResProc= rp;
  205.     return r;
  206. }
  207. void CDBL_Connection::Release()
  208. {
  209.     m_BR = 0;
  210.     // close all commands first
  211.     while(m_CMDs.NofItems() > 0) {
  212.         CDB_BaseEnt* pCmd = static_cast<CDB_BaseEnt*> (m_CMDs.Get(0));
  213.         delete pCmd;
  214.         m_CMDs.Remove((int) 0);
  215.     }
  216. }
  217. CDBL_Connection::~CDBL_Connection()
  218. {
  219.     Refresh();
  220.     dbclose(m_Link);
  221. }
  222. void CDBL_Connection::DropCmd(CDB_BaseEnt& cmd)
  223. {
  224.     m_CMDs.Remove(static_cast<TPotItem> (&cmd));
  225. }
  226. bool CDBL_Connection::x_SendData(I_ITDescriptor& descr_in,
  227.                                  CDB_Stream& stream, bool log_it)
  228. {
  229.     size_t size = stream.Size();
  230.     if (size < 1)
  231.         return false;
  232.     I_ITDescriptor* p_desc= 0;
  233.     // check what type of descriptor we've got
  234.     if(descr_in.DescriptorType() !=
  235. #ifndef MS_DBLIB_IN_USE
  236. CDBL_ITDESCRIPTOR_TYPE_MAGNUM
  237. #else
  238. CMSDBL_ITDESCRIPTOR_TYPE_MAGNUM
  239. #endif
  240. ){
  241. // this is not a native descriptor
  242. p_desc= x_GetNativeITDescriptor(dynamic_cast<CDB_ITDescriptor&> (descr_in));
  243. if(p_desc == 0) return false;
  244.     }
  245.     
  246.     C_ITDescriptorGuard d_guard(p_desc);
  247.     CDBL_ITDescriptor& desc = p_desc? dynamic_cast<CDBL_ITDescriptor&> (*p_desc) : 
  248. dynamic_cast<CDBL_ITDescriptor&> (descr_in);
  249.     char buff[1800]; // maximal page size
  250.     if (size <= sizeof(buff)) { // we could write a blob in one chunk
  251.         size_t s = stream.Read(buff, sizeof(buff));
  252.         if (dbwritetext(m_Link, (char*) desc.m_ObjName.c_str(),
  253.                         desc.m_TxtPtr_is_NULL ? 0 : desc.m_TxtPtr,
  254.                         DBTXPLEN,
  255.                         desc.m_TimeStamp_is_NULL ? 0 : desc.m_TimeStamp,
  256.                         log_it ? TRUE : FALSE, (DBINT) s, (BYTE*) buff)
  257.             != SUCCEED) {
  258.             throw CDB_ClientEx(eDB_Error, 210030, "CDBL_Connection::SendData",
  259.                                "dbwritetext failed");
  260.         }
  261.         return true;
  262.     }
  263.     // write it in chunks
  264.     if (dbwritetext(m_Link, (char*) desc.m_ObjName.c_str(),
  265.                     desc.m_TxtPtr_is_NULL ? 0 : desc.m_TxtPtr,
  266.                     DBTXPLEN,
  267.                     desc.m_TimeStamp_is_NULL ? 0 : desc.m_TimeStamp,
  268.                     log_it ? TRUE : FALSE, (DBINT) size, 0) != SUCCEED ||
  269.         dbsqlok(m_Link) != SUCCEED ||
  270.         //        dbresults(m_Link) == FAIL) {
  271.         x_Results(m_Link) == FAIL) {
  272.         throw CDB_ClientEx(eDB_Error, 210031, "CDBL_Connection::SendData",
  273.                            "dbwritetext/dbsqlok/dbresults failed");
  274.     }
  275.     while (size > 0) {
  276.         size_t s = stream.Read(buff, sizeof(buff));
  277.         if (s < 1) {
  278.             dbcancel(m_Link);
  279.             throw CDB_ClientEx(eDB_Fatal, 210032, "CDBL_Connection::SendData",
  280.                                "Text/Image data corrupted");
  281.         }
  282.         if (dbmoretext(m_Link, (DBINT) s, (BYTE*) buff) != SUCCEED) {
  283.             dbcancel(m_Link);
  284.             throw CDB_ClientEx(eDB_Error, 210033, "CDBL_Connection::SendData",
  285.                                "dbmoretext failed");
  286.         }
  287.         size -= s;
  288.     }
  289.     //    if (dbsqlok(m_Link) != SUCCEED || dbresults(m_Link) == FAIL) {
  290.     if (dbsqlok(m_Link) != SUCCEED || x_Results(m_Link) == FAIL) {
  291.         throw CDB_ClientEx(eDB_Error, 210034, "CDBL_Connection::SendData",
  292.                            "dbsqlok/dbresults failed");
  293.     }
  294.     return true;
  295. }
  296. I_ITDescriptor* CDBL_Connection::x_GetNativeITDescriptor(const CDB_ITDescriptor& descr_in)
  297. {
  298.     string q= "set rowcount 1nupdate ";
  299.     q+= descr_in.TableName();
  300.     q+= " set ";
  301.     q+= descr_in.ColumnName();
  302.     q+= "=NULL where ";
  303.     q+= descr_in.SearchConditions();
  304.     q+= " nselect ";
  305.     q+= descr_in.ColumnName();
  306.     q+= " from ";
  307.     q+= descr_in.TableName();
  308.     q+= " where ";
  309.     q+= descr_in.SearchConditions();
  310.     q+= " nset rowcount 0";
  311.     
  312.     CDB_LangCmd* lcmd= LangCmd(q, 0);
  313.     if(!lcmd->Send()) {
  314. throw CDB_ClientEx(eDB_Error, 210035, "CDBL_Connection::x_GetNativeITDescriptor",
  315.    "can not send the language command");
  316.     }
  317.     CDB_Result* res;
  318.     I_ITDescriptor* descr= 0;
  319.     bool i;
  320.     while(lcmd->HasMoreResults()) {
  321. res= lcmd->Result();
  322. if(res == 0) continue;
  323. if((res->ResultType() == eDB_RowResult) && (descr == 0)) {
  324.     EDB_Type tt= res->ItemDataType(0);
  325.     if(tt == eDB_Text || tt == eDB_Image) {
  326. while(res->Fetch()) {
  327.     res->ReadItem(&i, 1);
  328.     descr= new CDBL_ITDescriptor(m_Link, descr_in);
  329.     // descr= res->GetImageOrTextDescriptor();
  330.     if(descr) break;
  331. }
  332.     }
  333. }
  334. delete res;
  335.     }
  336.     delete lcmd;
  337.     return descr;
  338. }
  339. RETCODE CDBL_Connection::x_Results(DBPROCESS* pLink)
  340. {
  341.     unsigned int x_Status= 0x1;
  342.     CDB_Result* dbres;
  343.     I_Result* res= 0;
  344.     while ((x_Status & 0x1) != 0) {
  345.         if ((x_Status & 0x20) != 0) { // check for return parameters from exec
  346.             x_Status ^= 0x20;
  347.             int n;
  348.             if (m_ResProc && (n = dbnumrets(pLink)) > 0) {
  349.                 res = new CDBL_ParamResult(pLink, n);
  350.                 dbres= Create_Result(*res);
  351.                 m_ResProc->ProcessResult(*dbres);
  352.                 delete dbres;
  353.                 delete res;
  354.             }
  355.             continue;
  356.         }
  357.         if ((x_Status & 0x40) != 0) { // check for ret status
  358.             x_Status ^= 0x40;
  359.             if (m_ResProc && dbhasretstat(pLink)) {
  360.                 res = new CDBL_StatusResult(pLink);
  361.                 dbres= Create_Result(*res);
  362.                 m_ResProc->ProcessResult(*dbres);
  363.                 delete dbres;
  364.                 delete res;
  365.             }
  366.             continue;
  367.         }
  368.         if ((x_Status & 0x10) != 0) { // we do have a compute result
  369.             res = new CDBL_ComputeResult(pLink, &x_Status);
  370.             dbres= Create_Result(*res);
  371.             if(m_ResProc) {
  372.                 m_ResProc->ProcessResult(*dbres);
  373.             }
  374.             else {
  375.                 while(dbres->Fetch());
  376.             }
  377.             delete dbres;
  378.             delete res;
  379.         }
  380.         switch (dbresults(pLink)) {
  381.         case SUCCEED:
  382.             x_Status |= 0x60;
  383.             if (DBCMDROW(pLink) == SUCCEED) { // we could get rows in result
  384.                 if(!m_ResProc) {
  385.                     while(1) {
  386.                         switch(dbnextrow(pLink)) {
  387.                         case NO_MORE_ROWS:
  388.                         case FAIL:
  389.                         case BUF_FULL: break;
  390.                         default: continue;
  391.                         }
  392.                         break;
  393.                     }
  394.                     continue;
  395.                 }
  396.                             
  397. // This optimization is currently unavailable for MS dblib...
  398. #ifndef MS_DBLIB_IN_USE /*Text,Image*/
  399.                 if (dbnumcols(pLink) == 1) {
  400.                     int ct = dbcoltype(pLink, 1);
  401.                     if ((ct == SYBTEXT) || (ct == SYBIMAGE)) {
  402.                         res = new CDBL_BlobResult(pLink);
  403.                     }
  404.                 }
  405. #endif
  406.                 if (!res)
  407.                     res = new CDBL_RowResult(pLink, &x_Status);
  408.                 dbres= Create_Result(*res);
  409.                 m_ResProc->ProcessResult(*dbres);
  410.                 delete dbres;
  411.                 delete res;
  412.             } else {
  413.                 continue;
  414.             }
  415.         case NO_MORE_RESULTS:
  416.             x_Status = 2;
  417.             break;
  418.         default:
  419.             return FAIL;
  420.         }
  421.         break;
  422.     }
  423.     return SUCCEED;
  424. }
  425. /////////////////////////////////////////////////////////////////////////////
  426. //
  427. //  CDBL_SendDataCmd::
  428. //
  429. CDBL_SendDataCmd::CDBL_SendDataCmd(CDBL_Connection* con, DBPROCESS* cmd,
  430.                                    size_t nof_bytes)
  431. {
  432.     m_Connect  = con;
  433.     m_Cmd      = cmd;
  434.     m_Bytes2go = nof_bytes;
  435. }
  436. size_t CDBL_SendDataCmd::SendChunk(const void* pChunk, size_t nof_bytes)
  437. {
  438.     if (!pChunk  ||  !nof_bytes) {
  439.         throw CDB_ClientEx(eDB_Fatal, 290000, "CDBL_SendDataCmd::SendChunk",
  440.                            "wrong (zero) arguments");
  441.     }
  442.     if (!m_Bytes2go)
  443.         return 0;
  444.     if (nof_bytes > m_Bytes2go)
  445.         nof_bytes = m_Bytes2go;
  446.     if (dbmoretext(m_Cmd, (DBINT) nof_bytes, (BYTE*) pChunk) != SUCCEED) {
  447.         dbcancel(m_Cmd);
  448.         throw CDB_ClientEx(eDB_Error, 290001, "CDBL_SendDataCmd::SendChunk",
  449.                            "dbmoretext failed");
  450.     }
  451.     m_Bytes2go -= nof_bytes;
  452.     if (m_Bytes2go <= 0) {
  453.         //        if (dbsqlok(m_Cmd) != SUCCEED || dbresults(m_Cmd) == FAIL) {
  454.         if (dbsqlok(m_Cmd) != SUCCEED || m_Connect->x_Results(m_Cmd) == FAIL) {
  455.             throw CDB_ClientEx(eDB_Error, 290002,
  456.                                "CDBL_SendDataCmd::SendChunk",
  457.                                "dbsqlok/results failed");
  458.         }
  459.     }
  460.     return nof_bytes;
  461. }
  462. void CDBL_SendDataCmd::Release()
  463. {
  464.     m_BR = 0;
  465.     if (m_Bytes2go > 0) {
  466.         dbcancel(m_Cmd);
  467.         m_Bytes2go = 0;
  468.     }
  469.     m_Connect->DropCmd(*this);
  470.     delete this;
  471. }
  472. CDBL_SendDataCmd::~CDBL_SendDataCmd()
  473. {
  474.     if (m_Bytes2go > 0)
  475.         dbcancel(m_Cmd);
  476.     if (m_BR)
  477.         *m_BR = 0;
  478. }
  479. END_NCBI_SCOPE
  480. /*
  481.  * ===========================================================================
  482.  * $Log: connection.cpp,v $
  483.  * Revision 1000.1  2004/06/01 19:20:09  gouriano
  484.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.10
  485.  *
  486.  * Revision 1.10  2004/05/18 18:30:36  gorelenk
  487.  * PCH <ncbi_pch.hpp> moved to correct place .
  488.  *
  489.  * Revision 1.9  2004/05/17 21:12:41  gorelenk
  490.  * Added include of PCH ncbi_pch.hpp
  491.  *
  492.  * Revision 1.8  2003/06/05 16:01:13  soussov
  493.  * adds code for DumpResults and for the dumped results processing
  494.  *
  495.  * Revision 1.7  2002/08/23 16:31:47  soussov
  496.  * fixes bug in ~CDBL_Connection()
  497.  *
  498.  * Revision 1.6  2002/07/02 16:05:49  soussov
  499.  * splitting Sybase dblib and MS dblib
  500.  *
  501.  * Revision 1.5  2002/03/26 15:37:52  soussov
  502.  * new image/text operations added
  503.  *
  504.  * Revision 1.4  2002/01/08 18:10:18  sapojnik
  505.  * Syabse to MSSQL name translations moved to interface_p.hpp
  506.  *
  507.  * Revision 1.3  2001/10/24 16:39:01  lavr
  508.  * Explicit casts (where necessary) to eliminate 64->32 bit compiler warnings
  509.  *
  510.  * Revision 1.2  2001/10/22 16:28:01  lavr
  511.  * Default argument values removed
  512.  * (mistakenly left while moving code from header files)
  513.  *
  514.  * Revision 1.1  2001/10/22 15:19:55  lavr
  515.  * This is a major revamp (by Anton Lavrentiev, with help from Vladimir
  516.  * Soussov and Denis Vakatov) of the DBAPI "driver" libs originally
  517.  * written by Vladimir Soussov. The revamp follows the one of CTLib
  518.  * driver, and it involved massive code shuffling and grooming, numerous
  519.  * local API redesigns, adding comments and incorporating DBAPI to
  520.  * the C++ Toolkit.
  521.  *
  522.  * ===========================================================================
  523.  */