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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: context.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/16 17:20:27  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.31
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: context.cpp,v 1000.4 2004/06/16 17:20:27 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:  Driver for DBLib server
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbimtx.hpp>
  41. #ifndef USE_MS_DBLIB
  42. #  include <dbapi/driver/dblib/interfaces.hpp>
  43. #  include <dbapi/driver/dblib/interfaces_p.hpp>
  44. #else
  45. #  include <dbapi/driver/msdblib/interfaces.hpp>
  46. #  include <dbapi/driver/msdblib/interfaces_p.hpp>
  47. #endif
  48. #include <dbapi/driver/util/numeric_convert.hpp>
  49. BEGIN_NCBI_SCOPE
  50. /////////////////////////////////////////////////////////////////////////////
  51. //
  52. //  CDBLibContext::
  53. //
  54. extern "C" {
  55. #ifdef MS_DBLIB_IN_USE
  56.     static int s_DBLIB_err_callback
  57.     (DBPROCESS* dblink,   int   severity,
  58.      int        dberr,    int   oserr,
  59.      const char*  dberrstr, const char* oserrstr)
  60.     {
  61.         return CDBLibContext::DBLIB_dberr_handler
  62.             (dblink, severity, dberr, oserr, dberrstr? dberrstr : "",
  63.              oserrstr? oserrstr : "");
  64.     }
  65.     static int s_DBLIB_msg_callback
  66.     (DBPROCESS* dblink,   DBINT msgno,
  67.      int        msgstate, int   severity,
  68.      const char*      msgtxt,   const char* srvname,
  69.      const char*      procname, unsigned short   line)
  70.     {
  71.         CDBLibContext::DBLIB_dbmsg_handler
  72.             (dblink, msgno,   msgstate, severity,
  73.              msgtxt? msgtxt : "", srvname? srvname : "", procname? procname : "",
  74.              line);
  75.         return 0;
  76.     }
  77. #else
  78.     static int CS_PUBLIC s_DBLIB_err_callback
  79.     (DBPROCESS* dblink,   int   severity,
  80.      int        dberr,    int   oserr,
  81.      char*      dberrstr, char* oserrstr)
  82.     {
  83.         return CDBLibContext::DBLIB_dberr_handler
  84.             (dblink, severity, dberr, oserr, dberrstr? dberrstr : "",
  85.              oserrstr? oserrstr : "");
  86.     }
  87.     static int CS_PUBLIC s_DBLIB_msg_callback
  88.     (DBPROCESS* dblink,   DBINT msgno,
  89.      int        msgstate, int   severity,
  90.      char*      msgtxt,   char* srvname,
  91.      char*      procname, int   line)
  92.     {
  93.         CDBLibContext::DBLIB_dbmsg_handler
  94.             (dblink, msgno,   msgstate, severity,
  95.              msgtxt? msgtxt : "", srvname? srvname : "", procname? procname : "",
  96.              line);
  97.         return 0;
  98.     }
  99. #endif
  100. }
  101. CDBLibContext* CDBLibContext::m_pDBLibContext = 0;
  102. CDBLibContext::CDBLibContext(DBINT version) :
  103.     m_AppName("DBLibDriver"), m_HostName(""), m_PacketSize(0)
  104. {
  105.     DEFINE_STATIC_FAST_MUTEX(xMutex);
  106.     CFastMutexGuard mg(xMutex);
  107.     if (m_pDBLibContext != 0) {
  108.         throw CDB_ClientEx(eDB_Error, 200000, "CDBLibContext::CDBLibContext",
  109.                            "You cannot use more than one dblib context "
  110.                            "concurrently");
  111.     }
  112. #ifdef MS_DBLIB_IN_USE
  113.     if (dbinit() == NULL || version == 31415)
  114. #else
  115.         if (dbinit() != SUCCEED || dbsetversion(version) != SUCCEED)
  116. #endif
  117.             {
  118.                 throw CDB_ClientEx(eDB_Fatal, 200001, "CDBLibContext::CDBLibContext",
  119.                                    "dbinit failed");
  120.             }
  121.     dberrhandle(s_DBLIB_err_callback);
  122.     dbmsghandle(s_DBLIB_msg_callback);
  123.     m_pDBLibContext = this;
  124.     m_Login = dblogin();
  125. }
  126. bool CDBLibContext::SetLoginTimeout(unsigned int nof_secs)
  127. {
  128.     return dbsetlogintime(nof_secs) == SUCCEED;
  129. }
  130. bool CDBLibContext::SetTimeout(unsigned int nof_secs)
  131. {
  132.     return dbsettime(nof_secs) == SUCCEED;
  133. }
  134. bool CDBLibContext::SetMaxTextImageSize(size_t nof_bytes)
  135. {
  136.     char s[64];
  137.     sprintf(s, "%lu", (unsigned long) nof_bytes);
  138. #ifdef MS_DBLIB_IN_USE
  139.     return dbsetopt(0, DBTEXTLIMIT, s) == SUCCEED;
  140. #else
  141.     return dbsetopt(0, DBTEXTLIMIT, s, -1) == SUCCEED;
  142. #endif
  143. }
  144. CDB_Connection* CDBLibContext::Connect(const string&   srv_name,
  145.                                        const string&   user_name,
  146.                                        const string&   passwd,
  147.                                        TConnectionMode mode,
  148.                                        bool            reusable,
  149.                                        const string&   pool_name)
  150. {
  151.     CDBL_Connection* t_con;
  152.     // DEFINE_STATIC_FAST_MUTEX(xMutex);
  153.     CFastMutexGuard mg(m_Mtx);
  154.     if (reusable  &&  m_NotInUse.NofItems() > 0) { // try to reuse connection
  155.         if (!pool_name.empty()) { // try to use pool name
  156.             int n = m_NotInUse.NofItems();
  157.             while (n--) {
  158.                 t_con = static_cast<CDBL_Connection*> (m_NotInUse.Get(n));
  159.                 if (pool_name.compare(t_con->PoolName()) == 0) {
  160.                     m_NotInUse.Remove(n);
  161.                     if(t_con->Refresh()) {
  162.                         m_InUse.Add((TPotItem) t_con);
  163.                         return Create_Connection(*t_con);
  164.                     }
  165.                     delete t_con;
  166.                 }
  167.             }
  168.         }
  169.         else {
  170.             if (srv_name.empty())
  171.                 return 0;
  172.             int n = m_NotInUse.NofItems();
  173.             // try to use server name
  174.             while (n--) {
  175.                 t_con = static_cast<CDBL_Connection*> (m_NotInUse.Get(n));
  176.                 if (srv_name.compare(t_con->ServerName()) == 0) {
  177.                     m_NotInUse.Remove(n);
  178.                     if(t_con->Refresh()) {
  179.                         m_InUse.Add((TPotItem) t_con);
  180.                         return Create_Connection(*t_con);
  181.                     }
  182.                     delete t_con;
  183.                 }
  184.             }
  185.         }
  186.     }
  187.     if((mode & fDoNotConnect) != 0) return 0;
  188.     // new connection needed
  189.     if (srv_name.empty()  ||  user_name.empty()  ||  passwd.empty()) {
  190.         throw CDB_ClientEx(eDB_Error, 200010, "CDBLibContext::Connect",
  191.                            "Insufficient info/credentials to connect");
  192.     }
  193.     DBPROCESS* dbcon = x_ConnectToServer(srv_name, user_name, passwd, mode);
  194.     if (!dbcon) {
  195.         throw CDB_ClientEx(eDB_Error, 200011, "CDBLibContext::Connect",
  196.                            "Cannot connect to server");
  197.     }
  198. #ifdef MS_DBLIB_IN_USE
  199.     dbsetopt(dbcon, DBTEXTLIMIT, "0" ); // No limit
  200.     dbsetopt(dbcon, DBTEXTSIZE , "2147483647" ); // 0x7FFFFFFF
  201. #endif
  202.     t_con = new CDBL_Connection(this, dbcon, reusable, pool_name);
  203.     t_con->m_MsgHandlers = m_ConnHandlers;
  204.     t_con->m_Server      = srv_name;
  205.     t_con->m_User        = user_name;
  206.     t_con->m_Passwd      = passwd;
  207.     t_con->m_BCPAble     = (mode & fBcpIn) != 0;
  208.     t_con->m_SecureLogin = (mode & fPasswordEncrypted) != 0;
  209.     m_InUse.Add((TPotItem) t_con);
  210.     return Create_Connection(*t_con);
  211. }
  212. bool CDBLibContext::IsAbleTo(ECapability cpb) const
  213. {
  214.     switch(cpb) {
  215.     case eBcp:
  216.     case eReturnITDescriptors:
  217.     case eReturnComputeResults:
  218.         return true;
  219.     default:
  220.         break;
  221.     }
  222.     return false;
  223. }
  224. CDBLibContext::~CDBLibContext()
  225. {
  226.     CDBL_Connection* t_con;
  227.     // close all connections first
  228.     for (int i = m_NotInUse.NofItems(); i--; ) {
  229.         t_con = static_cast<CDBL_Connection*> (m_NotInUse.Get(i));
  230.         delete t_con;
  231.     }
  232.     for (int i = m_InUse.NofItems(); i--; ) {
  233.         t_con = static_cast<CDBL_Connection*> (m_InUse.Get(i));
  234.         delete t_con;
  235.     }
  236. #ifdef MS_DBLIB_IN_USE
  237.     dbfreelogin(m_Login);
  238. #else
  239.     dbloginfree(m_Login);
  240. #endif
  241.     dbexit();
  242.     m_pDBLibContext = 0;
  243. }
  244. void CDBLibContext::DBLIB_SetApplicationName(const string& app_name)
  245. {
  246.     m_AppName = app_name;
  247. }
  248. void CDBLibContext::DBLIB_SetHostName(const string& host_name)
  249. {
  250.     m_HostName = host_name;
  251. }
  252. void CDBLibContext::DBLIB_SetPacketSize(int p_size)
  253. {
  254.     m_PacketSize = (short) p_size;
  255. }
  256. bool CDBLibContext::DBLIB_SetMaxNofConns(int n)
  257. {
  258.     return dbsetmaxprocs(n) == SUCCEED;
  259. }
  260. int CDBLibContext::DBLIB_dberr_handler(DBPROCESS*    dblink,
  261.                                        int           severity,
  262.                                        int           dberr,
  263.                                        int           /*oserr*/,
  264.                                        const string& dberrstr,
  265.                                        const string& /*oserrstr*/)
  266. {
  267.     CDBL_Connection* link = dblink ?
  268.         reinterpret_cast<CDBL_Connection*> (dbgetuserdata(dblink)) : 0;
  269.     CDBHandlerStack* hs   = link ?
  270.         &link->m_MsgHandlers : &m_pDBLibContext->m_CntxHandlers;
  271.     switch (dberr) {
  272.     case SYBETIME:
  273.     case SYBEFCON:
  274.     case SYBECONN:
  275.         {
  276.             CDB_TimeoutEx to(dberr, "dblib", dberrstr);
  277.             hs->PostMsg(&to);
  278.         }
  279.         return INT_TIMEOUT;
  280.     default:
  281.         break;
  282.     }
  283.     switch (severity) {
  284.     case EXINFO:
  285.     case EXUSER:
  286.         {
  287.             CDB_ClientEx info(eDB_Info, dberr, "dblib", dberrstr);
  288.             hs->PostMsg(&info);
  289.         }
  290.         break;
  291.     case EXNONFATAL:
  292.     case EXCONVERSION:
  293.     case EXSERVER:
  294.     case EXPROGRAM:
  295.         {
  296.             CDB_ClientEx err(eDB_Error, dberr, "dblib", dberrstr);
  297.             hs->PostMsg(&err);
  298.         }
  299.         break;
  300.     case EXTIME:
  301.         {
  302.             CDB_TimeoutEx to(dberr, "dblib", dberrstr);
  303.             hs->PostMsg(&to);
  304.         }
  305.         return INT_TIMEOUT;
  306.     default:
  307.         {
  308.             CDB_ClientEx ftl(eDB_Fatal, dberr, "dblib", dberrstr);
  309.             hs->PostMsg(&ftl);
  310.         }
  311.         break;
  312.     }
  313.     return INT_CANCEL;
  314. }
  315. void CDBLibContext::DBLIB_dbmsg_handler(DBPROCESS*    dblink,
  316.                                         DBINT         msgno,
  317.                                         int           /*msgstate*/,
  318.                                         int           severity,
  319.                                         const string& msgtxt,
  320.                                         const string& srvname,
  321.                                         const string& procname,
  322.                                         int           line)
  323. {
  324.     if (msgno == 5701  ||  msgno == 5703)
  325.         return;
  326.     CDBL_Connection* link = dblink ?
  327.         reinterpret_cast<CDBL_Connection*>(dbgetuserdata(dblink)) : 0;
  328.     CDBHandlerStack* hs   = link ?
  329.         &link->m_MsgHandlers : &m_pDBLibContext->m_CntxHandlers;
  330.     if (msgno == 1205/*DEADLOCK*/) {
  331.         CDB_DeadlockEx dl(srvname, msgtxt);
  332.         hs->PostMsg(&dl);
  333.     } else {
  334.         EDB_Severity sev =
  335.             severity <  10 ? eDB_Info :
  336.             severity == 10 ? eDB_Warning :
  337.             severity <  16 ? eDB_Error :
  338.             severity >  16 ? eDB_Fatal :
  339.             eDB_Unknown;
  340.         if (!procname.empty()) {
  341.             CDB_RPCEx rpc(sev, msgno, srvname, msgtxt, procname, line);
  342.             hs->PostMsg(&rpc);
  343.         } else {
  344.             CDB_DSEx m(sev, msgno, srvname, msgtxt);
  345.             hs->PostMsg(&m);
  346.         }
  347.     }
  348. }
  349. DBPROCESS* CDBLibContext::x_ConnectToServer(const string&   srv_name,
  350.                                             const string&   user_name,
  351.                                             const string&   passwd,
  352.                                             TConnectionMode mode)
  353. {
  354.     if (!m_HostName.empty())
  355.         DBSETLHOST(m_Login, (char*) m_HostName.c_str());
  356.     if (m_PacketSize > 0)
  357.         DBSETLPACKET(m_Login, m_PacketSize);
  358.     if (DBSETLAPP (m_Login, (char*) m_AppName.c_str())
  359.         != SUCCEED ||
  360.         DBSETLUSER(m_Login, (char*) user_name.c_str())
  361.         != SUCCEED ||
  362.         DBSETLPWD (m_Login, (char*) passwd.c_str())
  363.         != SUCCEED)
  364.         return 0;
  365.     if (mode & fBcpIn)
  366.         BCP_SETL(m_Login, TRUE);
  367. #ifndef MS_DBLIB_IN_USE
  368.     if (mode & fPasswordEncrypted)
  369.         DBSETLENCRYPT(m_Login, TRUE);
  370. #endif
  371.     return dbopen(m_Login, (char*) srv_name.c_str());
  372. }
  373. ///////////////////////////////////////////////////////////////////////
  374. // Driver manager related functions
  375. //
  376. #ifndef MS_DBLIB_IN_USE
  377. I_DriverContext* DBLIB_CreateContext(map<string,string>* attr = 0)
  378. {
  379.     DBINT version= DBVERSION_46;
  380.     if(attr) {
  381.         string vers= (*attr)["version"];
  382.         if(vers.find("46") != string::npos)
  383.             version= DBVERSION_46;
  384.         else if(vers.find("100") != string::npos)
  385.             version= DBVERSION_100;
  386.     }
  387.     CDBLibContext* cntx= new CDBLibContext(version);
  388.     if(cntx && attr) {
  389.       string page_size= (*attr)["packet"];
  390.       if(!page_size.empty()) {
  391.     int s= atoi(page_size.c_str());
  392.     cntx->DBLIB_SetPacketSize(s);
  393.       }
  394.     }
  395.     return cntx;
  396. }
  397. void DBAPI_RegisterDriver_DBLIB(I_DriverMgr& mgr)
  398. {
  399.     mgr.RegisterDriver("dblib", DBLIB_CreateContext);
  400. }
  401. extern "C" {
  402.     NCBI_DBAPIDRIVER_DBLIB_EXPORT
  403.     void* DBAPI_E_dblib()
  404.     {
  405.         return (void*)DBAPI_RegisterDriver_DBLIB;
  406.     }
  407. }
  408. #else
  409. I_DriverContext* MSDBLIB_CreateContext(map<string,string>* attr = 0)
  410. {
  411.     DBINT version= DBVERSION_46;
  412.     return new CDBLibContext(version);
  413. }
  414. void DBAPI_RegisterDriver_MSDBLIB(I_DriverMgr& mgr)
  415. {
  416.     mgr.RegisterDriver("msdblib", MSDBLIB_CreateContext);
  417. }
  418. extern "C" {
  419.     NCBI_DBAPIDRIVER_MSDBLIB_EXPORT
  420.     void* DBAPI_E_msdblib()
  421.     {
  422.         return (void*)DBAPI_RegisterDriver_MSDBLIB;
  423.     }
  424. }
  425. #endif
  426. END_NCBI_SCOPE
  427. /*
  428.  * ===========================================================================
  429.  * $Log: context.cpp,v $
  430.  * Revision 1000.4  2004/06/16 17:20:27  gouriano
  431.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.31
  432.  *
  433.  * Revision 1.31  2004/06/16 16:08:51  ivanov
  434.  * Added export specifier for DBAPI_E_dblib()
  435.  *
  436.  * Revision 1.30  2004/05/17 21:12:41  gorelenk
  437.  * Added include of PCH ncbi_pch.hpp
  438.  *
  439.  * Revision 1.29  2004/04/08 12:18:35  ivanov
  440.  * Fixed name of export specifier for DBAPI_E_msdblib()
  441.  *
  442.  * Revision 1.28  2004/04/07 13:41:47  gorelenk
  443.  * Added export prefix to implementations of DBAPI_E_* functions.
  444.  *
  445.  * Revision 1.27  2003/11/14 20:46:21  soussov
  446.  * implements DoNotConnect mode
  447.  *
  448.  * Revision 1.26  2003/10/27 17:00:29  soussov
  449.  * adds code to prevent the return of broken connection from the pool
  450.  *
  451.  * Revision 1.25  2003/08/28 19:54:36  soussov
  452.  * allowes print messages go to handler
  453.  *
  454.  * Revision 1.24  2003/07/21 22:00:47  soussov
  455.  * fixes bug whith pool name mismatch in Connect()
  456.  *
  457.  * Revision 1.23  2003/07/17 20:46:02  soussov
  458.  * connections pool improvements
  459.  *
  460.  * Revision 1.22  2003/04/18 20:26:39  soussov
  461.  * fixes typo in Connect for reusable connection with specified connection pool
  462.  *
  463.  * Revision 1.21  2003/04/01 21:50:26  soussov
  464.  * new attribute 'packet=XXX' (where XXX is a packet size) added to DBLIB_CreateContext
  465.  *
  466.  * Revision 1.20  2002/12/20 17:56:33  soussov
  467.  * renames the members of ECapability enum
  468.  *
  469.  * Revision 1.19  2002/09/19 20:05:43  vasilche
  470.  * Safe initialization of static mutexes
  471.  *
  472.  * Revision 1.18  2002/07/10 15:47:46  soussov
  473.  * fixed typo in DBAPI_RegisterDriver_MSDBLIB
  474.  *
  475.  * Revision 1.17  2002/07/09 17:01:53  soussov
  476.  * the register functions for msdblib was renamed
  477.  *
  478.  * Revision 1.16  2002/07/02 16:05:49  soussov
  479.  * splitting Sybase dblib and MS dblib
  480.  *
  481.  * Revision 1.15  2002/06/19 15:02:03  soussov
  482.  * changes default version from unknown to 46
  483.  *
  484.  * Revision 1.14  2002/06/17 21:26:32  soussov
  485.  * dbsetversion added
  486.  *
  487.  * Revision 1.13  2002/04/19 15:05:50  soussov
  488.  * adds static mutex to Connect
  489.  *
  490.  * Revision 1.12  2002/04/12 22:13:09  soussov
  491.  * mutex protection for contex constructor added
  492.  *
  493.  * Revision 1.11  2002/03/26 15:37:52  soussov
  494.  * new image/text operations added
  495.  *
  496.  * Revision 1.10  2002/02/26 17:53:25  sapojnik
  497.  * Removed blob size limits for MS SQL
  498.  *
  499.  * Revision 1.9  2002/01/17 22:12:47  soussov
  500.  * changes driver registration
  501.  *
  502.  * Revision 1.8  2002/01/15 15:45:50  sapojnik
  503.  * Use DBVERSION_46/100 constants only ifndef NCBI_OS_MSWIN
  504.  *
  505.  * Revision 1.7  2002/01/11 20:25:08  soussov
  506.  * driver manager support added
  507.  *
  508.  * Revision 1.6  2002/01/08 18:10:18  sapojnik
  509.  * Syabse to MSSQL name translations moved to interface_p.hpp
  510.  *
  511.  * Revision 1.5  2002/01/03 17:01:56  sapojnik
  512.  * fixing CR/LF mixup
  513.  *
  514.  * Revision 1.4  2002/01/03 15:46:23  sapojnik
  515.  * ported to MS SQL (about 12 'ifdef NCBI_OS_MSWIN' in 6 files)
  516.  *
  517.  * Revision 1.3  2001/10/24 16:40:00  lavr
  518.  * Comment out unused function arguments
  519.  *
  520.  * Revision 1.2  2001/10/22 18:38:49  soussov
  521.  * sending NULL instead of emty string fixed
  522.  *
  523.  * Revision 1.1  2001/10/22 15:19:55  lavr
  524.  * This is a major revamp (by Anton Lavrentiev, with help from Vladimir
  525.  * Soussov and Denis Vakatov) of the DBAPI "driver" libs originally
  526.  * written by Vladimir Soussov. The revamp follows the one of CTLib
  527.  * driver, and it involved massive code shuffling and grooming, numerous
  528.  * local API redesigns, adding comments and incorporating DBAPI to
  529.  * the C++ Toolkit.
  530.  *
  531.  * ===========================================================================
  532.  */