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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: context.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:21:44  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.14
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: context.cpp,v 1000.4 2004/06/01 19:21:44 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 ODBC server
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbimtx.hpp>
  41. #include <dbapi/driver/odbc/interfaces.hpp>
  42. #include <dbapi/driver/util/numeric_convert.hpp>
  43. #ifdef HAVE_ODBCSS_H
  44. #include <odbcss.h>
  45. #endif
  46. BEGIN_NCBI_SCOPE
  47. /////////////////////////////////////////////////////////////////////////////
  48. //
  49. //  CODBC_Reporter::
  50. //
  51. void CODBC_Reporter::ReportErrors()
  52. {
  53.     SQLINTEGER NativeError;
  54.     SQLSMALLINT MsgLen;
  55.     SQLCHAR SqlState[6];
  56.     SQLCHAR Msg[1024];
  57.     if(!m_HStack) return;
  58.     for(SQLSMALLINT i= 1; i < 128; i++) {
  59.         switch(SQLGetDiagRec(m_HType, m_Handle, i, SqlState, &NativeError, 
  60.                              Msg, sizeof(Msg), &MsgLen)) {
  61.         case SQL_SUCCESS:
  62.             if(strncmp((const char*)SqlState, "HYT", 3) == 0) { // timeout
  63.                 CDB_TimeoutEx to(NativeError, "odbc", (const char*)Msg);
  64.                 m_HStack->PostMsg(&to);
  65.             }
  66.             else if(strncmp((const char*)SqlState, "40001", 5) == 0) { // deadlock
  67.                 CDB_DeadlockEx dl("odbc", (const char*)Msg);
  68.                 m_HStack->PostMsg(&dl);
  69.             }
  70.             else if(NativeError != 5701 && NativeError != 5703){
  71.                 CDB_SQLEx se(eDB_Unknown, NativeError, "odbc", (const char*)Msg, 
  72. (const char*)SqlState, 0);
  73.                 m_HStack->PostMsg(&se);
  74.             }
  75.             continue;
  76.         case SQL_NO_DATA: break;
  77.         case SQL_SUCCESS_WITH_INFO:
  78.             {
  79.                 CDB_DSEx dse(eDB_Unknown, 777, "odbc", "Message is too long to be retrieved");
  80.                 m_HStack->PostMsg(&dse);
  81.             }
  82.             continue;
  83.         default:
  84.             {
  85.                 CDB_ClientEx ce(eDB_Warning, 420016, "CODBC_Reporter::ReportErrors",
  86.                                 "SQLGetDiagRec failed (memory corruption suspected)");
  87.                 m_HStack->PostMsg(&ce);
  88.             }
  89.             break;
  90.         }
  91.         break;
  92.     }
  93. }
  94. /////////////////////////////////////////////////////////////////////////////
  95. //
  96. //  CODBCContext::
  97. //
  98. CODBCContext::CODBCContext(SQLINTEGER version, bool use_dsn) : m_Reporter(0, SQL_HANDLE_ENV, 0)
  99. {
  100.     if(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_Context) != SQL_SUCCESS) {
  101.         throw CDB_ClientEx(eDB_Fatal, 400001, "CODBCContext::CODBCContext",
  102.                            "Can not allocate a context");
  103.     }
  104.     m_Reporter.SetHandle(m_Context);
  105.     m_Reporter.SetHandlerStack(&m_CntxHandlers);
  106.     SQLSetEnvAttr(m_Context, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)version, 0);
  107.     
  108.     m_PacketSize= 0;
  109.     m_LoginTimeout= 0;
  110.     m_Timeout= 0;
  111.     m_TextImageSize= 0;
  112.     m_UseDSN= use_dsn;
  113. }
  114. bool CODBCContext::SetLoginTimeout(unsigned int nof_secs)
  115. {
  116.     m_LoginTimeout= (SQLUINTEGER)nof_secs;
  117.     return true;
  118. }
  119. bool CODBCContext::SetTimeout(unsigned int nof_secs)
  120. {
  121.     m_Timeout= (SQLUINTEGER)nof_secs;
  122.     for (int i = m_NotInUse.NofItems(); i--;) {
  123.         CODBC_Connection* t_con
  124.             = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  125.         t_con->ODBC_SetTimeout(m_Timeout);
  126.     }
  127.     for (int i = m_InUse.NofItems(); i--;) {
  128.         CODBC_Connection* t_con
  129.             = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  130.         t_con->ODBC_SetTimeout(m_Timeout);
  131.     }
  132.     return true;
  133. }
  134. bool CODBCContext::SetMaxTextImageSize(size_t nof_bytes)
  135. {
  136.     m_TextImageSize = (SQLUINTEGER) nof_bytes;
  137.     for (int i = m_NotInUse.NofItems(); i--;) {
  138.         CODBC_Connection* t_con
  139.             = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  140.         t_con->ODBC_SetTextImageSize(m_TextImageSize);
  141.     }
  142.     
  143.     for (int i = m_InUse.NofItems(); i--;) {
  144.         CODBC_Connection* t_con
  145.             = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  146.         t_con->ODBC_SetTextImageSize(m_TextImageSize);
  147.     }
  148.     return true;
  149. }
  150. CDB_Connection* CODBCContext::Connect(const string&   srv_name,
  151.                                       const string&   user_name,
  152.                                       const string&   passwd,
  153.                                       TConnectionMode mode,
  154.                                       bool            reusable,
  155.                                       const string&   pool_name)
  156. {
  157.     // static CFastMutex xMutex;
  158.     CFastMutexGuard mg(m_Mtx);
  159.     if (reusable  &&  m_NotInUse.NofItems() > 0) {
  160.         // try to get a connection from the pot
  161.         if ( !pool_name.empty() ) {
  162.             // use a pool name
  163.             for (int i = m_NotInUse.NofItems();  i--; ) {
  164.                 CODBC_Connection* t_con
  165.                     = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  166.                 if (pool_name.compare(t_con->PoolName()) == 0) {
  167.                     m_NotInUse.Remove(i);
  168.                     if(t_con->Refresh()) {
  169.                         m_InUse.Add((TPotItem) t_con);
  170.                         return Create_Connection(*t_con);
  171.                     }
  172.                     delete t_con;
  173.                 }
  174.             }
  175.         }
  176.         else {
  177.             if ( srv_name.empty() )
  178.                 return 0;
  179.             
  180.             // try to use a server name
  181.             for (int i = m_NotInUse.NofItems();  i--; ) {
  182.                 CODBC_Connection* t_con
  183.                     = static_cast<CODBC_Connection*> (m_NotInUse.Get(i));
  184.                 
  185.                 if (srv_name.compare(t_con->ServerName()) == 0) {
  186.                     m_NotInUse.Remove(i);
  187.                     if(t_con->Refresh()) {
  188.                         m_InUse.Add((TPotItem) t_con);
  189.                         return Create_Connection(*t_con);
  190.                     }
  191.                     delete t_con;
  192.                 }
  193.             }
  194.         }
  195.     }
  196.     if((mode & fDoNotConnect) != 0) return 0;
  197.     // new connection needed
  198.     if (srv_name.empty()  ||  user_name.empty()  ||  passwd.empty()) {
  199.         throw CDB_ClientEx(eDB_Error, 100010, "CODBCContext::Connect",
  200.                            "You have to provide server name, user name and "
  201.                            "password to connect to the server");
  202.     }
  203.     SQLHDBC con = x_ConnectToServer(srv_name, user_name, passwd, mode);
  204.     if (con == 0) {
  205.         throw CDB_ClientEx(eDB_Error, 100011, "CODBCContext::Connect",
  206.                            "Cannot connect to the server");
  207.     }
  208.     CODBC_Connection* t_con = new CODBC_Connection(this, con, reusable, pool_name);
  209.     t_con->m_MsgHandlers = m_ConnHandlers;
  210.     t_con->m_Server      = srv_name;
  211.     t_con->m_User        = user_name;
  212.     t_con->m_Passwd      = passwd;
  213. //    t_con->m_BCPAble     = (mode & fBcpIn) != 0;
  214.     t_con->m_SecureLogin = (mode & fPasswordEncrypted) != 0;
  215.     m_InUse.Add((TPotItem) t_con);
  216.     return Create_Connection(*t_con);
  217. }
  218. CODBCContext::~CODBCContext()
  219. {
  220.     if ( !m_Context ) {
  221.         return;
  222.     }
  223.     // close all connections first
  224.     for (int i = m_NotInUse.NofItems();  i--; ) {
  225.         CODBC_Connection* t_con = static_cast<CODBC_Connection*>(m_NotInUse.Get(i));
  226.         delete t_con;
  227.     }
  228.     for (int i = m_InUse.NofItems();  i--; ) {
  229.         CODBC_Connection* t_con = static_cast<CODBC_Connection*> (m_InUse.Get(i));
  230.         delete t_con;
  231.     }
  232. SQLFreeHandle(SQL_HANDLE_ENV, m_Context);
  233. }
  234. void CODBCContext::ODBC_SetPacketSize(SQLUINTEGER packet_size)
  235. {
  236.     m_PacketSize = packet_size;
  237. }
  238. SQLHENV CODBCContext::ODBC_GetContext() const
  239. {
  240.     return m_Context;
  241. }
  242. SQLHDBC CODBCContext::x_ConnectToServer(const string&   srv_name,
  243.                                                const string&   user_name,
  244.                                                const string&   passwd,
  245.                                                TConnectionMode mode)
  246. {
  247.     SQLHDBC con;
  248.     SQLRETURN r;
  249.     r= SQLAllocHandle(SQL_HANDLE_DBC, m_Context, &con);
  250.     if((r != SQL_SUCCESS) && (r != SQL_SUCCESS_WITH_INFO))
  251.         return 0;
  252.     if(m_Timeout) {
  253.         SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (void*)m_Timeout, 0);
  254.     }
  255.     
  256.     if(m_LoginTimeout) {
  257.         SQLSetConnectAttr(con, SQL_ATTR_LOGIN_TIMEOUT, (void*)m_LoginTimeout, 0);
  258.     }
  259.     
  260.     if(m_PacketSize) {
  261.         SQLSetConnectAttr(con, SQL_ATTR_PACKET_SIZE, (void*)m_PacketSize, 0);
  262.     }
  263.     
  264. #ifdef SQL_COPT_SS_BCP
  265.     if((mode & fBcpIn) != 0) {
  266.         SQLSetConnectAttr(con, SQL_COPT_SS_BCP, (void*) SQL_BCP_ON, SQL_IS_INTEGER);
  267.     }
  268. #endif
  269.     if(!m_UseDSN) {
  270. #ifdef NCBI_OS_MSWIN
  271.       string connect_str("DRIVER={SQL Server};SERVER=");
  272. #else
  273.       string connect_str("DSN=");
  274. #endif
  275.         connect_str+= srv_name;
  276.         connect_str+= ";UID=";
  277.         connect_str+= user_name;
  278.         connect_str+= ";PWD=";
  279.         connect_str+= passwd;
  280.         r= SQLDriverConnect(con, 0, (SQLCHAR*) connect_str.c_str(), SQL_NTS, 
  281.                             0, 0, 0, SQL_DRIVER_NOPROMPT);
  282.     }
  283.     else {
  284.         r= SQLConnect(con, (SQLCHAR*) srv_name.c_str(), SQL_NTS,
  285.                    (SQLCHAR*) user_name.c_str(), SQL_NTS,
  286.                    (SQLCHAR*) passwd.c_str(), SQL_NTS);
  287.     }
  288.     switch(r) {
  289.     case SQL_SUCCESS_WITH_INFO:
  290.         xReportConError(con);
  291.     case SQL_SUCCESS: return con;
  292.         
  293.     case SQL_ERROR:
  294.         xReportConError(con);
  295.         SQLFreeHandle(SQL_HANDLE_DBC, con);
  296.         break;
  297.     default:
  298.         m_Reporter.ReportErrors();
  299.         break;
  300.     }
  301.     
  302.     return 0;
  303. }
  304. void CODBCContext::xReportConError(SQLHDBC con)
  305. {
  306. m_Reporter.SetHandleType(SQL_HANDLE_DBC);
  307.     m_Reporter.SetHandle(con);
  308. m_Reporter.ReportErrors();
  309. m_Reporter.SetHandleType(SQL_HANDLE_ENV);
  310.     m_Reporter.SetHandle(m_Context);
  311. }
  312. /////////////////////////////////////////////////////////////////////////////
  313. //
  314. //  Miscellaneous
  315. //
  316. ///////////////////////////////////////////////////////////////////////
  317. // Driver manager related functions
  318. //
  319. I_DriverContext* ODBC_CreateContext(map<string,string>* attr = 0)
  320. {
  321.     SQLINTEGER version= SQL_OV_ODBC3;
  322.     bool use_dsn= false;
  323.     if(attr) {
  324.         string vers= (*attr)["version"];
  325.         if(vers.find("3") != string::npos)
  326.             version= SQL_OV_ODBC3;
  327.         else if(vers.find("2") != string::npos)
  328.             version= SQL_OV_ODBC2;
  329.         use_dsn= (*attr)["use_dsn"] == "true";
  330.     }
  331.     CODBCContext* cntx=  new CODBCContext(version, use_dsn);
  332.     if(cntx && attr) {
  333.       string page_size= (*attr)["packet"];
  334.       if(!page_size.empty()) {
  335. SQLUINTEGER s= atoi(page_size.c_str());
  336. cntx->ODBC_SetPacketSize(s);
  337.       }
  338.     }
  339.     return cntx;
  340. }
  341. NCBI_DBAPIDRIVER_ODBC_EXPORT
  342. void DBAPI_RegisterDriver_ODBC(I_DriverMgr& mgr)
  343. {
  344.     mgr.RegisterDriver("odbc", ODBC_CreateContext);
  345. }
  346. extern "C" {
  347.     NCBI_DBAPIDRIVER_ODBC_EXPORT
  348.     void* DBAPI_E_odbc()
  349.     {
  350.         return (void*)DBAPI_RegisterDriver_ODBC;
  351.     }
  352. }
  353. END_NCBI_SCOPE
  354. /*
  355.  * ===========================================================================
  356.  * $Log: context.cpp,v $
  357.  * Revision 1000.4  2004/06/01 19:21:44  gouriano
  358.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.14
  359.  *
  360.  * Revision 1.14  2004/05/17 21:16:05  gorelenk
  361.  * Added include of PCH ncbi_pch.hpp
  362.  *
  363.  * Revision 1.13  2004/04/07 13:41:48  gorelenk
  364.  * Added export prefix to implementations of DBAPI_E_* functions.
  365.  *
  366.  * Revision 1.12  2004/03/17 19:25:38  gorelenk
  367.  * Added NCBI_DBAPIDRIVER_ODBC_EXPORT export prefix for definition of
  368.  * DBAPI_RegisterDriver_ODBC .
  369.  *
  370.  * Revision 1.11  2003/11/14 20:46:51  soussov
  371.  * implements DoNotConnect mode
  372.  *
  373.  * Revision 1.10  2003/10/27 17:00:53  soussov
  374.  * adds code to prevent the return of broken connection from the pool
  375.  *
  376.  * Revision 1.9  2003/07/21 21:58:08  soussov
  377.  * fixes bug whith pool name mismatch in Connect()
  378.  *
  379.  * Revision 1.8  2003/07/18 19:20:34  soussov
  380.  * removes SetPacketSize function
  381.  *
  382.  * Revision 1.7  2003/07/17 20:47:10  soussov
  383.  * connections pool improvements
  384.  *
  385.  * Revision 1.6  2003/05/08 20:48:33  soussov
  386.  * adding datadirect-odbc type of connecting string. Rememner that you need ODBCINI environment variable to make it works
  387.  *
  388.  * Revision 1.5  2003/05/05 20:48:29  ucko
  389.  * Check HAVE_ODBCSS_H; fix some typos in an error message.
  390.  *
  391.  * Revision 1.4  2003/04/01 21:51:17  soussov
  392.  * new attribute 'packet=XXX' (where XXX is a packet size) added to ODBC_CreateContext
  393.  *
  394.  * Revision 1.3  2002/07/03 21:48:50  soussov
  395.  * adds DSN support if needed
  396.  *
  397.  * Revision 1.2  2002/07/02 20:52:54  soussov
  398.  * adds RegisterDriver for ODBC
  399.  *
  400.  * Revision 1.1  2002/06/18 22:06:24  soussov
  401.  * initial commit
  402.  *
  403.  *
  404.  * ===========================================================================
  405.  */