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

生物技术

开发平台:

C/C++

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