src/dbapi/driver/ctlib/context.cpp

Go to the documentation of this file.
00001 /* $Id: context.cpp 145603 2008-11-13 21:13:10Z ssikorsk $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author:  Vladimir Soussov
00027  *
00028  * File Description:  Driver for CTLib client library
00029  *
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 
00034 #include "ctlib_utils.hpp"
00035 
00036 #include <corelib/plugin_manager_impl.hpp>
00037 #include <corelib/plugin_manager_store.hpp>
00038 #include <corelib/ncbi_param.hpp>
00039 
00040 // DO NOT DELETE this include !!!
00041 #include <dbapi/driver/driver_mgr.hpp>
00042 
00043 #include <dbapi/driver/dbapi_driver_conn_mgr.hpp>
00044 #include <dbapi/driver/ctlib/interfaces.hpp>
00045 #include <dbapi/driver/util/pointer_pot.hpp>
00046 #include <dbapi/error_codes.hpp>
00047 
00048 #include <algorithm>
00049 
00050 #if defined(NCBI_OS_MSWIN)
00051 #  include <winsock2.h>
00052 #  include "../ncbi_win_hook.hpp"
00053 #else
00054 #  include <unistd.h>
00055 #endif
00056 
00057 #ifdef FTDS_IN_USE
00058 #  include "config.h"
00059 #  include "tds.h"
00060 #endif
00061 
00062 #define NCBI_USE_ERRCODE_X   Dbapi_CTLib_Context
00063 
00064 
00065 BEGIN_NCBI_SCOPE
00066 
00067 #ifdef FTDS_IN_USE
00068 namespace ftds64_ctlib
00069 {
00070 #endif
00071 
00072 /////////////////////////////////////////////////////////////////////////////
00073 inline
00074 CDiagCompileInfo GetBlankCompileInfo(void)
00075 {
00076     return CDiagCompileInfo();
00077 }
00078 
00079 
00080 #ifdef FTDS_IN_USE
00081 #   define s_CTLCtxMtx  s_TDSCtxMtx
00082 #endif
00083 
00084 /// Static mutex which will guard all thread-unsafe operations on all ctlib
00085 /// contexts. It is added because several CTLibContext classes can share one
00086 /// global underlying context handle, so there is no other way to synchronize
00087 /// them but some global mutex. Use of non-global context handles considered
00088 /// to be very rare so the impact on using it through global mutex can be
00089 /// treated as insignificant.
00090 DEFINE_STATIC_MUTEX(s_CTLCtxMtx);
00091 
00092 
00093 /////////////////////////////////////////////////////////////////////////////
00094 //
00095 //  CTLibContextRegistry (Singleton)
00096 //
00097 
00098 class  CTLibContextRegistry
00099 {
00100 public:
00101     static CTLibContextRegistry& Instance(void);
00102 
00103     void Add(CTLibContext* ctx);
00104     void Remove(CTLibContext* ctx);
00105     void ClearAll(void);
00106     static void StaticClearAll(void);
00107 
00108     bool ExitProcessIsPatched(void) const
00109     {
00110         return m_ExitProcessPatched;
00111     }
00112 
00113 private:
00114     CTLibContextRegistry(void);
00115     ~CTLibContextRegistry(void) throw();
00116 
00117     mutable CMutex          m_Mutex;
00118     vector<CTLibContext*>   m_Registry;
00119     bool                    m_ExitProcessPatched;
00120 
00121     friend class CSafeStaticPtr<CTLibContextRegistry>;
00122 };
00123 
00124 
00125 /////////////////////////////////////////////////////////////////////////////
00126 CTLibContextRegistry::CTLibContextRegistry(void) :
00127 m_ExitProcessPatched(false)
00128 {
00129 #if defined(NCBI_OS_MSWIN) && defined(NCBI_DLL_BUILD)
00130 
00131     try {
00132         m_ExitProcessPatched = 
00133             NWinHook::COnExitProcess::Instance().Add(CTLibContextRegistry::StaticClearAll);
00134     } catch (const NWinHook::CWinHookException&) {
00135         // Just in case ...
00136         m_ExitProcessPatched = false;
00137     }
00138 
00139 #endif
00140 }
00141 
00142 CTLibContextRegistry::~CTLibContextRegistry(void) throw()
00143 {
00144     try {
00145         ClearAll();
00146     }
00147     NCBI_CATCH_ALL_X( 6, NCBI_CURRENT_FUNCTION )
00148 }
00149 
00150 CTLibContextRegistry&
00151 CTLibContextRegistry::Instance(void)
00152 {
00153     static CSafeStaticPtr<CTLibContextRegistry> instance;
00154 
00155     return instance.Get();
00156 }
00157 
00158 void
00159 CTLibContextRegistry::Add(CTLibContext* ctx)
00160 {
00161     CMutexGuard mg(m_Mutex);
00162 
00163     vector<CTLibContext*>::iterator it = find(m_Registry.begin(),
00164                                               m_Registry.end(),
00165                                               ctx);
00166     if (it == m_Registry.end()) {
00167         m_Registry.push_back(ctx);
00168     }
00169 }
00170 
00171 void
00172 CTLibContextRegistry::Remove(CTLibContext* ctx)
00173 {
00174     CMutexGuard mg(m_Mutex);
00175 
00176     vector<CTLibContext*>::iterator it = find(m_Registry.begin(),
00177                                               m_Registry.end(),
00178                                               ctx);
00179 
00180     if (it != m_Registry.end()) {
00181         m_Registry.erase(it);
00182         ctx->x_SetRegistry(NULL);
00183     }
00184 }
00185 
00186 
00187 void
00188 CTLibContextRegistry::ClearAll(void)
00189 {
00190     if (!m_Registry.empty())
00191     {
00192         CMutexGuard mg(m_Mutex);
00193         CMutexGuard ctx_mg(s_CTLCtxMtx);
00194 
00195         while ( !m_Registry.empty() ) {
00196             // x_Close will unregister and remove handler from the registry.
00197             m_Registry.back()->x_Close(false);
00198         }
00199     }
00200 }
00201 
00202 void
00203 CTLibContextRegistry::StaticClearAll(void)
00204 {
00205     CTLibContextRegistry::Instance().ClearAll();
00206 }
00207 
00208 
00209 /////////////////////////////////////////////////////////////////////////////
00210 namespace ctlib
00211 {
00212 
00213 Connection::Connection(CTLibContext& context,
00214                        CTL_Connection& ctl_conn)
00215 : m_CTL_Context(&context)
00216 , m_CTL_Conn(&ctl_conn)
00217 , m_Handle(NULL)
00218 , m_IsAllocated(false)
00219 , m_IsOpen(false)
00220 , m_IsDead(false)
00221 {
00222     if (GetCTLContext().Check(ct_con_alloc(GetCTLContext().CTLIB_GetContext(),
00223                                    &m_Handle)) != CS_SUCCEED) {
00224         DATABASE_DRIVER_ERROR( "Cannot allocate a connection handle.", 100011 );
00225     }
00226     m_IsAllocated = true;
00227 }
00228 
00229 
00230 Connection::~Connection(void) throw()
00231 {
00232     try {
00233         // Connection must be closed before it is allowed to be dropped.
00234         Close();
00235         Drop();
00236     }
00237     NCBI_CATCH_ALL_X( 7, NCBI_CURRENT_FUNCTION )
00238 }
00239 
00240 
00241 bool Connection::Drop(void)
00242 {
00243     // Connection must be dropped always, even if it is dead.
00244     if (m_IsAllocated) {
00245         GetCTLConn().Check(ct_con_drop(m_Handle));
00246         m_IsAllocated = false;
00247     }
00248 
00249     return !m_IsAllocated;
00250 }
00251 
00252 
00253 const CTL_Connection&
00254 Connection::GetCTLConn(void) const
00255 {
00256     if (!m_CTL_Conn) {
00257         DATABASE_DRIVER_ERROR( "CTL_Connection wasn't assigned.", 100011 );
00258     }
00259 
00260     return *m_CTL_Conn;
00261 }
00262 
00263 
00264 CTL_Connection&
00265 Connection::GetCTLConn(void)
00266 {
00267     if (!m_CTL_Conn) {
00268         DATABASE_DRIVER_ERROR( "CTL_Connection wasn't assigned.", 100011 );
00269     }
00270 
00271     return *m_CTL_Conn;
00272 }
00273 
00274 
00275 bool Connection::Open(const CDBConnParams& params)
00276 {
00277     if (!IsOpen() || Close()) {
00278         CS_RETCODE rc;
00279 
00280         string server_name;
00281 
00282 #if defined(FTDS_IN_USE)
00283         if (params.GetHost()) {
00284             server_name = impl::ConvertN2A(params.GetHost());
00285             if (params.GetPort()) {
00286                 server_name += ":" + NStr::IntToString(params.GetPort());
00287             }
00288         } else {
00289             server_name = params.GetServerName();
00290         }
00291 
00292         rc = GetCTLContext().Check(ct_connect(GetNativeHandle(),
00293                                 const_cast<char*> (server_name.c_str()),
00294                                 CS_NULLTERM));
00295 #else
00296 #if defined(CS_SERVERADDR)
00297         if (params.GetHost()) {
00298             server_name = impl::ConvertN2A(params.GetHost());
00299             if (params.GetPort()) {
00300                 server_name += " " + NStr::IntToString(params.GetPort());
00301             }
00302 
00303             GetCTLContext().Check(ct_con_props(GetNativeHandle(),
00304                                 CS_SET,
00305                                 CS_SERVERADDR,
00306                                 (CS_VOID*)server_name.c_str(),
00307                                 server_name.size(),
00308                                 NULL));
00309 
00310             rc = GetCTLContext().Check(ct_connect(GetNativeHandle(),
00311                                     NULL,
00312                                     CS_UNUSED));
00313         } else {
00314             server_name = params.GetServerName();
00315 
00316             rc = GetCTLContext().Check(ct_connect(GetNativeHandle(),
00317                         const_cast<char*> (server_name.c_str()),
00318                         CS_NULLTERM));
00319         }
00320 #else
00321         server_name = params.GetServerName();
00322 
00323         rc = GetCTLContext().Check(ct_connect(GetNativeHandle(),
00324                                 const_cast<char*> (server_name.c_str()),
00325                                 CS_NULLTERM));
00326 
00327 #endif
00328 #endif
00329 
00330         if (rc == CS_SUCCEED) {
00331             m_IsOpen = true;
00332         }
00333     }
00334 
00335     return IsOpen();
00336 }
00337 
00338 
00339 bool Connection::Close(void)
00340 {
00341     if (IsOpen()) {
00342         if (IsDead()) {
00343             if (GetCTLConn().Check(ct_close(GetNativeHandle(), CS_FORCE_CLOSE)) == CS_SUCCEED) {
00344                 m_IsOpen = false;
00345             }
00346         } else {
00347             if (GetCTLConn().Check(ct_close(GetNativeHandle(), CS_UNUSED)) == CS_SUCCEED) {
00348                 m_IsOpen = false;
00349             }
00350         }
00351     }
00352 
00353     return !IsOpen();
00354 }
00355 
00356 
00357 bool Connection::Cancel(void)
00358 {
00359     if (IsOpen()) {
00360         if (!IsAlive()) {
00361             return false;
00362         }
00363 
00364         if (GetCTLConn().Check(ct_cancel(
00365             GetNativeHandle(),
00366             NULL,
00367             CS_CANCEL_ALL) != CS_SUCCEED)) {
00368             return false;
00369         }
00370     }
00371 
00372     return true;
00373 }
00374 
00375 
00376 bool Connection::IsAlive(void)
00377 {
00378     CS_INT status;
00379     if (GetCTLConn().Check(ct_con_props(
00380         GetNativeHandle(),
00381         CS_GET,
00382         CS_CON_STATUS,
00383         &status,
00384         CS_UNUSED,
00385         0)) != CS_SUCCEED) {
00386         return false;
00387     }
00388 
00389     return
00390         (status & CS_CONSTAT_CONNECTED) != 0  &&
00391         (status & CS_CONSTAT_DEAD     ) == 0;
00392 }
00393 
00394 
00395 bool Connection::IsOpen_native(void)
00396 {
00397     CS_INT is_logged = CS_TRUE;
00398 
00399 #if !defined(FTDS_IN_USE)
00400     GetCTLConn().Check(ct_con_props(
00401         GetNativeHandle(),
00402         CS_GET,
00403         CS_LOGIN_STATUS,
00404         (CS_VOID*)&is_logged,
00405         CS_UNUSED,
00406         NULL)
00407     );
00408 #endif
00409 
00410     return is_logged == CS_TRUE;
00411 }
00412 
00413 
00414 ////////////////////////////////////////////////////////////////////////////////
00415 Command::Command(CTL_Connection& ctl_conn)
00416 : m_CTL_Conn(&ctl_conn)
00417 , m_Handle(NULL)
00418 , m_IsAllocated(false)
00419 , m_IsOpen(false)
00420 {
00421     if (GetCTLConn().Check(ct_cmd_alloc(
00422                            GetCTLConn().GetNativeConnection().GetNativeHandle(),
00423                            &m_Handle
00424                            )) != CS_SUCCEED) {
00425         DATABASE_DRIVER_ERROR("Cannot allocate a command handle.", 100011);
00426     }
00427 
00428     m_IsAllocated = true;
00429 }
00430 
00431 
00432 Command::~Command(void)
00433 {
00434     try {
00435         Close();
00436         Drop();
00437     }
00438     NCBI_CATCH_ALL_X( 8, NCBI_CURRENT_FUNCTION )
00439 }
00440 
00441 
00442 bool
00443 Command::Open(CS_INT type, CS_INT option, const string& arg)
00444 {
00445     _ASSERT(!m_IsOpen);
00446 
00447     if (!m_IsOpen) {
00448         m_IsOpen = (GetCTLConn().Check(ct_command(m_Handle,
00449                                                   type,
00450                                                   (CS_CHAR*)arg .c_str(),
00451                                                   arg.size(),
00452                                                   option)) == CS_SUCCEED);
00453     }
00454 
00455     return m_IsOpen;
00456 }
00457 
00458 
00459 bool
00460 Command::GetDataInfo(CS_IODESC& desc)
00461 {
00462     return (GetCTLConn().Check(ct_data_info(
00463         m_Handle,
00464         CS_GET,
00465         CS_UNUSED,
00466         &desc)) == CS_SUCCEED);
00467 }
00468 
00469 
00470 bool
00471 Command::SendData(CS_VOID* buff, CS_INT buff_len)
00472 {
00473     return (GetCTLConn().Check(ct_send_data(
00474         m_Handle,
00475         buff,
00476         buff_len)) == CS_SUCCEED);
00477 }
00478 
00479 
00480 bool
00481 Command::Send(void)
00482 {
00483     return (GetCTLConn().Check(ct_send(
00484         m_Handle)) == CS_SUCCEED);
00485 }
00486 
00487 
00488 CS_RETCODE
00489 Command::GetResults(CS_INT& res_type)
00490 {
00491     return GetCTLConn().Check(ct_results(m_Handle, &res_type));
00492 }
00493 
00494 
00495 CS_RETCODE
00496 Command::Fetch(void)
00497 {
00498     return GetCTLConn().Check(ct_fetch(
00499         m_Handle,
00500         CS_UNUSED,
00501         CS_UNUSED,
00502         CS_UNUSED,
00503         0));
00504 }
00505 
00506 
00507 void
00508 Command::Drop(void)
00509 {
00510     if (m_IsAllocated) {
00511         GetCTLConn().Check(ct_cmd_drop(m_Handle));
00512         m_Handle = NULL;
00513         m_IsAllocated = false;
00514     }
00515 }
00516 
00517 
00518 void
00519 Command::Close(void)
00520 {
00521     if (m_IsOpen) {
00522         GetCTLConn().Check(ct_cancel(NULL, m_Handle, CS_CANCEL_ALL));
00523         m_IsOpen = false;
00524     }
00525 }
00526 
00527 
00528 } // namespace ctlib
00529 
00530 
00531 /////////////////////////////////////////////////////////////////////////////
00532 //
00533 //  CTLibContext::
00534 //
00535 
00536 CTLibContext::CTLibContext(bool reuse_context, CS_INT version) :
00537     m_Context(NULL),
00538     m_Locale(NULL),
00539     m_PacketSize(2048),
00540     m_LoginRetryCount(0),
00541     m_LoginLoopDelay(0),
00542     m_TDSVersion(version),
00543     m_Registry(NULL)
00544 {
00545 #ifdef FTDS_IN_USE
00546     switch (version) {
00547         case 40:
00548         case 42:
00549         case 46:
00550         case CS_VERSION_100:
00551             DATABASE_DRIVER_ERROR("FTDS driver does not support TDS protocol "
00552                                   "version other than 5.0 or 7.0.",
00553                                   300011 );
00554             break;
00555     }
00556 #endif
00557 
00558     CMutexGuard mg(s_CTLCtxMtx);
00559 
00560     ResetEnvSybase();
00561 
00562     SetApplicationName("CTLibDriver");
00563 
00564     CS_RETCODE r = reuse_context ? Check(cs_ctx_global(version, &m_Context)) :
00565         Check(cs_ctx_alloc(version, &m_Context));
00566     if (r != CS_SUCCEED) {
00567         m_Context = 0;
00568         DATABASE_DRIVER_ERROR( "Cannot allocate a context", 100001 );
00569     }
00570 
00571 
00572     r = cs_loc_alloc(CTLIB_GetContext(), &m_Locale);
00573     if (r != CS_SUCCEED) {
00574         m_Locale = NULL;
00575     }
00576 
00577     CS_VOID*     cb;
00578     CS_INT       outlen;
00579     CPointerPot* p_pot = 0;
00580 
00581     // check if cs message callback is already installed
00582     r = Check(cs_config(CTLIB_GetContext(), CS_GET, CS_MESSAGE_CB, &cb, CS_UNUSED, &outlen));
00583     if (r != CS_SUCCEED) {
00584         m_Context = 0;
00585         DATABASE_DRIVER_ERROR( "cs_config failed", 100006 );
00586     }
00587 
00588     if (cb == (CS_VOID*)  CTLIB_cserr_handler) {
00589         // we did use this context already
00590         r = Check(cs_config(CTLIB_GetContext(), CS_GET, CS_USERDATA,
00591                       (CS_VOID*) &p_pot, (CS_INT) sizeof(p_pot), &outlen));
00592         if (r != CS_SUCCEED) {
00593             m_Context = 0;
00594             DATABASE_DRIVER_ERROR( "cs_config failed", 100006 );
00595         }
00596     }
00597     else {
00598         // this is a brand new context
00599         r = Check(cs_config(CTLIB_GetContext(), CS_SET, CS_MESSAGE_CB,
00600                       (CS_VOID*) CTLIB_cserr_handler, CS_UNUSED, NULL));
00601         if (r != CS_SUCCEED) {
00602             Check(cs_ctx_drop(CTLIB_GetContext()));
00603             m_Context = 0;
00604             DATABASE_DRIVER_ERROR( "Cannot install the cslib message callback", 100005 );
00605         }
00606 
00607         p_pot = new CPointerPot;
00608         r = Check(cs_config(CTLIB_GetContext(), CS_SET, CS_USERDATA,
00609                       (CS_VOID*) &p_pot, (CS_INT) sizeof(p_pot), NULL));
00610         if (r != CS_SUCCEED) {
00611             Check(cs_ctx_drop(CTLIB_GetContext()));
00612             m_Context = 0;
00613             delete p_pot;
00614             DATABASE_DRIVER_ERROR( "Cannot install the user data", 100007 );
00615         }
00616 
00617         r = Check(ct_init(CTLIB_GetContext(), version));
00618         if (r != CS_SUCCEED) {
00619             Check(cs_ctx_drop(CTLIB_GetContext()));
00620             m_Context = 0;
00621             delete p_pot;
00622             DATABASE_DRIVER_ERROR( "ct_init failed", 100002 );
00623         }
00624 
00625         r = Check(ct_callback(CTLIB_GetContext(), NULL, CS_SET, CS_CLIENTMSG_CB,
00626                         (CS_VOID*) CTLIB_cterr_handler));
00627         if (r != CS_SUCCEED) {
00628             Check(ct_exit(CTLIB_GetContext(), CS_FORCE_EXIT));
00629             Check(cs_ctx_drop(CTLIB_GetContext()));
00630             m_Context = 0;
00631             delete p_pot;
00632             DATABASE_DRIVER_ERROR( "Cannot install the client message callback", 100003 );
00633         }
00634 
00635         r = Check(ct_callback(CTLIB_GetContext(), NULL, CS_SET, CS_SERVERMSG_CB,
00636                         (CS_VOID*) CTLIB_srverr_handler));
00637         if (r != CS_SUCCEED) {
00638             Check(ct_exit(CTLIB_GetContext(), CS_FORCE_EXIT));
00639             Check(cs_ctx_drop(CTLIB_GetContext()));
00640             m_Context = 0;
00641             delete p_pot;
00642             DATABASE_DRIVER_ERROR( "Cannot install the server message callback", 100004 );
00643         }
00644         // PushCntxMsgHandler();
00645     }
00646 
00647     if ( p_pot ) {
00648         p_pot->Add((TPotItem) this);
00649     }
00650 
00651     m_Registry = &CTLibContextRegistry::Instance();
00652     x_AddToRegistry();
00653 }
00654 
00655 
00656 CTLibContext::~CTLibContext()
00657 {
00658     CMutexGuard mg(s_CTLCtxMtx);
00659 
00660     try {
00661         x_Close();
00662 
00663         if (m_Locale) {
00664             cs_loc_drop(CTLIB_GetContext(), m_Locale);
00665             m_Locale = NULL;
00666         }
00667     }
00668     NCBI_CATCH_ALL_X( 9, NCBI_CURRENT_FUNCTION )
00669 }
00670 
00671 
00672 CS_RETCODE
00673 CTLibContext::Check(CS_RETCODE rc) const
00674 {
00675     GetCTLExceptionStorage().Handle(GetCtxHandlerStack(), GetExtraMsg());
00676 
00677     return rc;
00678 }
00679 
00680 
00681 void
00682 CTLibContext::x_AddToRegistry(void)
00683 {
00684     if (m_Registry) {
00685         m_Registry->Add(this);
00686     }
00687 }
00688 
00689 void
00690 CTLibContext::x_RemoveFromRegistry(void)
00691 {
00692     if (m_Registry) {
00693         m_Registry->Remove(this);
00694     }
00695 }
00696 
00697 void
00698 CTLibContext::x_SetRegistry(CTLibContextRegistry* registry)
00699 {
00700     m_Registry = registry;
00701 }
00702 
00703 bool CTLibContext::SetLoginTimeout(unsigned int nof_secs)
00704 {
00705     impl::CDriverContext::SetLoginTimeout(nof_secs);
00706 
00707     CMutexGuard mg(s_CTLCtxMtx);
00708 
00709     int sec = (nof_secs == 0 ? CS_NO_LIMIT : static_cast<int>(nof_secs));
00710 
00711     return Check(ct_config(CTLIB_GetContext(),
00712                            CS_SET,
00713                            CS_LOGIN_TIMEOUT,
00714                            &sec,
00715                            CS_UNUSED,
00716                            NULL)) == CS_SUCCEED;
00717 }
00718 
00719 
00720 bool CTLibContext::SetTimeout(unsigned int nof_secs)
00721 {
00722     bool success = impl::CDriverContext::SetTimeout(nof_secs);
00723 
00724     CMutexGuard mg(s_CTLCtxMtx);
00725 
00726     int sec = (nof_secs == 0 ? CS_NO_LIMIT : static_cast<int>(nof_secs));
00727 
00728     if (Check(ct_config(CTLIB_GetContext(),
00729                         CS_SET,
00730                         CS_TIMEOUT,
00731                         &sec,
00732                         CS_UNUSED,
00733                         NULL)) == CS_SUCCEED
00734         ) {
00735         return success;
00736     }
00737 
00738     return false;
00739 }
00740 
00741 
00742 bool CTLibContext::SetMaxTextImageSize(size_t nof_bytes)
00743 {
00744     impl::CDriverContext::SetMaxTextImageSize(nof_bytes);
00745 
00746     CMutexGuard mg(s_CTLCtxMtx);
00747 
00748     CS_INT ti_size = (CS_INT) GetMaxTextImageSize();
00749     return Check(ct_config(CTLIB_GetContext(),
00750                            CS_SET,
00751                            CS_TEXTLIMIT,
00752                            &ti_size,
00753                            CS_UNUSED,
00754                            NULL)) == CS_SUCCEED;
00755 }
00756 
00757 
00758 unsigned int
00759 CTLibContext::GetLoginTimeout(void) const
00760 {
00761     {
00762         // For the sake of Check() and HandlerStack()
00763         CMutexGuard mg(s_CTLCtxMtx);
00764 
00765         CS_INT t_out = 0;
00766 
00767         if (Check(ct_config(CTLIB_GetContext(),
00768                             CS_GET,
00769                             CS_LOGIN_TIMEOUT,
00770                             &t_out,
00771                             CS_UNUSED,
00772                             NULL)) == CS_SUCCEED) {
00773             return t_out;
00774         }
00775     }
00776 
00777     return impl::CDriverContext::GetLoginTimeout();
00778 }
00779 
00780 
00781 unsigned int CTLibContext::GetTimeout(void) const
00782 {
00783     {
00784         // For the sake of Check() and HandlerStack()
00785         CMutexGuard mg(s_CTLCtxMtx);
00786 
00787         CS_INT t_out = 0;
00788 
00789         if (Check(ct_config(CTLIB_GetContext(),
00790                             CS_GET,
00791                             CS_TIMEOUT,
00792                             &t_out,
00793                             CS_UNUSED,
00794                             NULL)) == CS_SUCCEED) {
00795             return t_out;
00796         }
00797     }
00798 
00799     return impl::CDriverContext::GetTimeout();
00800 }
00801 
00802 
00803 impl::CConnection*
00804 CTLibContext::MakeIConnection(const CDBConnParams& params)
00805 {
00806     CMutexGuard mg(s_CTLCtxMtx);
00807 
00808     return new CTL_Connection(*this, params);
00809 }
00810 
00811 
00812 bool CTLibContext::IsAbleTo(ECapability cpb) const
00813 {
00814     switch(cpb) {
00815     case eBcp:
00816     case eReturnITDescriptors:
00817     case eReturnComputeResults:
00818         return true;
00819     default:
00820         break;
00821     }
00822 
00823     return false;
00824 }
00825 
00826 
00827 bool
00828 CTLibContext::SetMaxConnect(unsigned int num)
00829 {
00830     CMutexGuard mg(s_CTLCtxMtx);
00831 
00832     return Check(ct_config(CTLIB_GetContext(),
00833                            CS_SET,
00834                            CS_MAX_CONNECT,
00835                            (CS_VOID*)&num,
00836                            CS_UNUSED,
00837                            NULL)) == CS_SUCCEED;
00838 }
00839 
00840 
00841 unsigned int
00842 CTLibContext::GetMaxConnect(void)
00843 {
00844     // For the sake of Check() and HandlerStack()
00845     CMutexGuard mg(s_CTLCtxMtx);
00846 
00847     unsigned int num = 0;
00848 
00849     if (Check(ct_config(CTLIB_GetContext(),
00850                         CS_GET,
00851                         CS_MAX_CONNECT,
00852                         (CS_VOID*)&num,
00853                         CS_UNUSED,
00854                         NULL)) != CS_SUCCEED) {
00855         return 0;
00856     }
00857 
00858     return num;
00859 }
00860 
00861 
00862 void
00863 CTLibContext::x_Close(bool delete_conn)
00864 {
00865     if ( CTLIB_GetContext() ) {
00866         if (x_SafeToFinalize()) {
00867             if (delete_conn) {
00868                 DeleteAllConn();
00869             } else {
00870                 CloseAllConn();
00871             }
00872         }
00873 
00874         CS_INT       outlen;
00875         CPointerPot* p_pot = 0;
00876 
00877         if (Check(cs_config(CTLIB_GetContext(),
00878                         CS_GET,
00879                         CS_USERDATA,
00880                         (void*) &p_pot,
00881                         (CS_INT) sizeof(p_pot),
00882                         &outlen)) == CS_SUCCEED
00883             &&  p_pot != 0) {
00884             p_pot->Remove(this);
00885             if (p_pot->NofItems() == 0) {
00886                 if (x_SafeToFinalize()) {
00887                     if (Check(ct_exit(CTLIB_GetContext(),
00888                                         CS_UNUSED)) != CS_SUCCEED) {
00889                         Check(ct_exit(CTLIB_GetContext(),
00890                                         CS_FORCE_EXIT));
00891                     }
00892 
00893                     // This is a last driver for this context
00894                     // Clean context user data ...
00895                     {
00896                         CPointerPot* p_pot_tmp = NULL;
00897                         Check(cs_config(CTLIB_GetContext(),
00898                                         CS_SET,
00899                                         CS_USERDATA,
00900                                         (CS_VOID*) &p_pot_tmp,
00901                                         (CS_INT) sizeof(p_pot_tmp),
00902                                         NULL
00903                                         )
00904                               );
00905 
00906                         delete p_pot;
00907                     }
00908 
00909                     Check(cs_ctx_drop(CTLIB_GetContext()));
00910                 }
00911             }
00912         }
00913 
00914         m_Context = NULL;
00915         x_RemoveFromRegistry();
00916     } else {
00917         if (delete_conn && x_SafeToFinalize()) {
00918             DeleteAllConn();
00919         }
00920     }
00921 }
00922 
00923 bool CTLibContext::x_SafeToFinalize(void) const
00924 {
00925     if (m_Registry) {
00926 #if defined(NCBI_OS_MSWIN)
00927         return m_Registry->ExitProcessIsPatched();
00928 #endif
00929     }
00930 
00931     return true;
00932 }
00933 
00934 void CTLibContext::CTLIB_SetApplicationName(const string& a_name)
00935 {
00936     SetApplicationName( a_name );
00937 }
00938 
00939 
00940 void CTLibContext::CTLIB_SetHostName(const string& host_name)
00941 {
00942     SetHostName( host_name );
00943 }
00944 
00945 
00946 void CTLibContext::CTLIB_SetPacketSize(CS_INT packet_size)
00947 {
00948     m_PacketSize = packet_size;
00949 }
00950 
00951 
00952 void CTLibContext::CTLIB_SetLoginRetryCount(CS_INT n)
00953 {
00954     m_LoginRetryCount = n;
00955 }
00956 
00957 
00958 void CTLibContext::CTLIB_SetLoginLoopDelay(CS_INT nof_sec)
00959 {
00960     m_LoginLoopDelay = nof_sec;
00961 }
00962 
00963 
00964 CS_CONTEXT* CTLibContext::CTLIB_GetContext() const
00965 {
00966     return m_Context;
00967 }
00968 
00969 
00970 CS_RETCODE CTLibContext::CTLIB_cserr_handler(CS_CONTEXT* context, CS_CLIENTMSG* msg)
00971 {
00972     EDiagSev sev = eDiag_Error;
00973 
00974     if (msg->severity == CS_SV_INFORM) {
00975         sev = eDiag_Info;
00976     }
00977     else if (msg->severity == CS_SV_FATAL) {
00978         sev = eDiag_Critical;
00979     }
00980 
00981 
00982 #ifdef FTDS_IN_USE
00983     if ((msg->msgnumber & 0xFF) == 25) {
00984         CDB_TruncateEx ex(
00985             GetBlankCompileInfo(),
00986             0,
00987             msg->msgstring,
00988             msg->msgnumber);
00989 
00990         ex.SetSybaseSeverity(msg->severity);
00991         GetCTLExceptionStorage().Accept(ex);
00992         return CS_SUCCEED;
00993     }
00994 #endif
00995 
00996     try {
00997         CDB_ClientEx ex(
00998             GetBlankCompileInfo(),
00999             0, msg->msgstring,
01000             sev,
01001             msg->msgnumber
01002             );
01003 
01004         ex.SetSybaseSeverity(msg->severity);
01005 
01006         GetCTLExceptionStorage().Accept(ex);
01007     } catch (...) {
01008         return CS_FAIL;
01009     }
01010 
01011     return CS_SUCCEED;
01012 }
01013 
01014 
01015 static
01016 void PassException(CDB_Exception& ex,
01017                    const string&  server_name,
01018                    const string&  user_name,
01019                    CS_INT         severity
01020                    )
01021 {
01022     ex.SetServerName(server_name);
01023     ex.SetUserName(user_name);
01024     ex.SetSybaseSeverity(severity);
01025 
01026     GetCTLExceptionStorage().Accept(ex);
01027 }
01028 
01029 
01030 static
01031 CS_RETCODE
01032 HandleConnStatus(CS_CONNECTION* conn,
01033                  CS_CLIENTMSG*  msg,
01034                  const string&  server_name,
01035                  const string&  user_name
01036                  )
01037 {
01038     if(conn) {
01039         CS_INT login_status = 0;
01040 
01041         if( ct_con_props(conn,
01042                          CS_GET,
01043                          CS_LOGIN_STATUS,
01044                          (CS_VOID*)&login_status,
01045                          CS_UNUSED,
01046                          NULL) != CS_SUCCEED) {
01047             return CS_FAIL;
01048         }
01049 
01050         if (login_status) {
01051             CS_RETCODE rc = ct_cancel(conn, NULL, CS_CANCEL_ATTN);
01052 
01053             switch(rc){
01054             case CS_SUCCEED:
01055                 return CS_SUCCEED;
01056 #if !defined(FTDS_IN_USE)
01057             case CS_TRYING: {
01058                 CDB_TimeoutEx ex(
01059                     GetBlankCompileInfo(),
01060                     0,
01061                     "Got timeout on ct_cancel(CS_CANCEL_ALL)",
01062                     msg->msgnumber);
01063 
01064                 PassException(ex, server_name, user_name, msg->severity);
01065             }
01066 #endif
01067             default:
01068                 return CS_FAIL;
01069             }
01070         }
01071     }
01072 
01073     return CS_FAIL;
01074 }
01075 
01076 
01077 CS_RETCODE CTLibContext::CTLIB_cterr_handler(CS_CONTEXT* context,
01078                                              CS_CONNECTION* con,
01079                                              CS_CLIENTMSG* msg
01080                                              )
01081 {
01082     CS_INT          outlen;
01083     CPointerPot*    p_pot = 0;
01084     CTL_Connection* link = 0;
01085     string          message;
01086     string          server_name;
01087     string          user_name;
01088 
01089     try {
01090         if (msg->msgstring) {
01091             message.append(msg->msgstring);
01092         }
01093 
01094         // Retrieve CDBHandlerStack ...
01095         if (con != NULL  &&
01096             ct_con_props(con,
01097                          CS_GET,
01098                          CS_USERDATA,
01099                          (void*) &link,
01100                          (CS_INT) sizeof(link),
01101                          &outlen ) == CS_SUCCEED  &&  link != 0) {
01102             if (link->ServerName().size() < 127 && link->UserName().size() < 127) {
01103                 server_name = link->ServerName();
01104                 user_name = link->UserName();
01105             } else {
01106                 ERR_POST_X(1, Error << "Invalid value of ServerName." << CStackTrace());
01107             }
01108         }
01109         else if (cs_config(context,
01110                            CS_GET,
01111                            CS_USERDATA,
01112                            (void*) &p_pot,
01113                            (CS_INT) sizeof(p_pot),
01114                            &outlen ) == CS_SUCCEED  &&
01115                  p_pot != 0  &&  p_pot->NofItems() > 0) {
01116             // CTLibContext* drv = (CTLibContext*) p_pot->Get(0);
01117         }
01118         else {
01119             if (msg->severity != CS_SV_INFORM) {
01120                 ostrstream err_str;
01121 
01122                 // nobody can be informed, let's put it in stderr
01123                 err_str << "CTLIB error handler detects the following error" << endl
01124                         << "Severity:" << msg->severity << err_str << " Msg # "
01125                         << msg->msgnumber << endl;
01126                 err_str << msg->msgstring << endl;
01127 
01128                 if (msg->osstringlen > 1) {
01129                     err_str << "OS # "    << msg->osnumber
01130                             << " OS msg " << msg->osstring << endl;
01131                 }
01132 
01133                 if (msg->sqlstatelen > 1  &&
01134                     (msg->sqlstate[0] != 'Z' || msg->sqlstate[1] != 'Z')) {
01135                     err_str << "SQL: " << msg->sqlstate << endl;
01136                 }
01137 
01138                 ERR_POST_X(2, (string)CNcbiOstrstreamToString(err_str));
01139             }
01140 
01141             return CS_SUCCEED;
01142         }
01143 
01144         // In case of timeout ...
01145         /* Experimental. Based on C-Toolkit and code developed by Eugene
01146          * Yaschenko.
01147         if (msg->msgnumber == 16908863) {
01148             return HandleConnStatus(con, msg, server_name, user_name);
01149         }
01150         */
01151 
01152 #ifdef FTDS_IN_USE
01153         if ((msg->msgnumber & 0xFF) == 25) {
01154             CDB_TruncateEx ex(
01155                 GetBlankCompileInfo(),
01156                 0,
01157                 message,
01158                 msg->msgnumber);
01159 
01160             PassException(ex, server_name, user_name, msg->severity);
01161             return CS_SUCCEED;
01162         }
01163 #endif
01164 
01165         // Process the message ...
01166         switch (msg->severity) {
01167         case CS_SV_INFORM: {
01168             CDB_ClientEx ex( GetBlankCompileInfo(),
01169                                0,
01170                                message,
01171                                eDiag_Info,
01172                                msg->msgnumber);
01173 
01174             PassException(ex, server_name, user_name, msg->severity);
01175 
01176             break;
01177         }
01178         case CS_SV_RETRY_FAIL: {
01179             CDB_TimeoutEx ex(
01180                 GetBlankCompileInfo(),
01181                 0,
01182                 message,
01183                 msg->msgnumber);
01184 
01185             PassException(ex, server_name, user_name, msg->severity);
01186 
01187             return HandleConnStatus(con, msg, server_name, user_name);
01188 
01189             break;
01190         }
01191         case CS_SV_CONFIG_FAIL:
01192         case CS_SV_API_FAIL:
01193         case CS_SV_INTERNAL_FAIL: {
01194             CDB_ClientEx ex( GetBlankCompileInfo(),
01195                               0,
01196                               message,
01197                               eDiag_Error,
01198                               msg->msgnumber);
01199 
01200             PassException(ex, server_name, user_name, msg->severity);
01201 
01202             break;
01203         }
01204         default: {
01205             CDB_ClientEx ex(
01206                 GetBlankCompileInfo(),
01207                 0,
01208                 message,
01209                 eDiag_Critical,
01210                 msg->msgnumber);
01211 
01212             PassException(ex, server_name, user_name, msg->severity);
01213 
01214             break;
01215         }
01216         }
01217     } catch (...) {
01218         return CS_FAIL;
01219     }
01220 
01221     return CS_SUCCEED;
01222 }
01223 
01224 
01225 CS_RETCODE CTLibContext::CTLIB_srverr_handler(CS_CONTEXT* context,
01226                                               CS_CONNECTION* con,
01227                                               CS_SERVERMSG* msg
01228                                               )
01229 {
01230     if (
01231         /* (msg->severity == 0  &&  msg->msgnumber == 0)  ||*/
01232         // commented out because nobody remember why it is there and PubSeqOS does
01233         // send messages with 0 0 that need to be processed
01234         msg->msgnumber == 3621 ||  // The statement has been terminated.
01235         msg->msgnumber == 3980 ||  // The request failed to run because the batch is aborted...
01236         msg->msgnumber == 5701 ||
01237         msg->msgnumber == 5703 ||
01238         msg->msgnumber == 5704
01239         ) {
01240         return CS_SUCCEED;
01241     }
01242 
01243     CS_INT          outlen;
01244     CPointerPot*    p_pot = 0;
01245     CTL_Connection* link = 0;
01246     string          message;
01247     string          server_name;
01248     string          user_name;
01249 
01250     try {
01251         if (con != NULL && ct_con_props(con, CS_GET, CS_USERDATA,
01252                                        (void*) &link, (CS_INT) sizeof(link),
01253                                        &outlen) == CS_SUCCEED  &&
01254             link != NULL) {
01255             if (link->ServerName().size() < 127 && link->UserName().size() < 127) {
01256                 server_name = link->ServerName();
01257                 user_name = link->UserName();
01258             } else {
01259                 ERR_POST_X(3, Error << "Invalid value of ServerName." << CStackTrace());
01260             }
01261         }
01262         else if (cs_config(context, CS_GET,
01263                            CS_USERDATA,
01264                            (void*) &p_pot,
01265                            (CS_INT) sizeof(p_pot),
01266                            &outlen) == CS_SUCCEED  &&
01267                  p_pot != 0  &&  p_pot->NofItems() > 0) {
01268 
01269             // CTLibContext* drv = (CTLibContext*) p_pot->Get(0);
01270             server_name = string(msg->svrname, msg->svrnlen);
01271         }
01272         else {
01273             ostrstream err_str;
01274 
01275             err_str << "Message from the server ";
01276 
01277             if (msg->svrnlen > 0) {
01278                 err_str << "<" << msg->svrname << "> ";
01279             }
01280 
01281             err_str << "msg # " << msg->msgnumber
01282                     << " severity: " << msg->severity << endl;
01283 
01284             if (msg->proclen > 0) {
01285                 err_str << "Proc: " << msg->proc << " line: " << msg->line << endl;
01286             }
01287 
01288             if (msg->sqlstatelen > 1  &&
01289                 (msg->sqlstate[0] != 'Z'  ||  msg->sqlstate[1] != 'Z')) {
01290                 err_str << "SQL: " << msg->sqlstate << endl;
01291             }
01292 
01293             err_str << msg->text << endl;
01294 
01295             ERR_POST_X(4, (string)CNcbiOstrstreamToString(err_str));
01296 
01297             return CS_SUCCEED;
01298         }
01299 
01300         if ( msg->text ) {
01301             message += msg->text;
01302         }
01303 
01304         if (msg->msgnumber == 1205 /*DEADLOCK*/) {
01305             CDB_DeadlockEx ex(GetBlankCompileInfo(),
01306                               0,
01307                               message);
01308 
01309             PassException(ex, server_name, user_name, msg->severity);
01310         }
01311         else if (msg->msgnumber == 1771  ||  msg->msgnumber == 1708) {
01312             // "Maximum row size exceeds allowable width. It is being rounded down to 32767 bytes."
01313             // "Row size (32767 bytes) could exceed row size limit, which is 1962 bytes."
01314             // and in ftds
01315             // "The table has been created but its maximum row size exceeds the maximum number of bytes
01316             //  per row (8060). INSERT or UPDATE of a row in this table will fail if the resulting row
01317             //  length exceeds 8060 bytes."
01318             ERR_POST_X(11, Warning << message);
01319         }
01320         else {
01321             EDiagSev sev =
01322                 msg->severity <  10 ? eDiag_Info :
01323                 msg->severity == 10 ? (msg->msgnumber == 0 ? eDiag_Info : eDiag_Warning) :
01324                 msg->severity <  16 ? eDiag_Error : eDiag_Critical;
01325 
01326             if (msg->proclen > 0) {
01327                 CDB_RPCEx ex(GetBlankCompileInfo(),
01328                               0,
01329                               message,
01330                               sev,
01331                               (int) msg->msgnumber,
01332                               msg->proc,
01333                               (int) msg->line);
01334 
01335                 PassException(ex, server_name, user_name, msg->severity);
01336             }
01337             else if (msg->sqlstatelen > 1  &&
01338                      (msg->sqlstate[0] != 'Z'  ||  msg->sqlstate[1] != 'Z')) {
01339                 CDB_SQLEx ex(GetBlankCompileInfo(),
01340                               0,
01341                               message,
01342                               sev,
01343                               (int) msg->msgnumber,
01344                               (const char*) msg->sqlstate,
01345                               (int) msg->line);
01346 
01347                 PassException(ex, server_name, user_name, msg->severity);
01348             }
01349             else {
01350                 CDB_DSEx ex(GetBlankCompileInfo(),
01351                             0,
01352                             message,
01353                             sev,
01354                             (int) msg->msgnumber);
01355 
01356                 PassException(ex, server_name, user_name, msg->severity);
01357             }
01358         }
01359     } catch (...) {
01360         return CS_FAIL;
01361     }
01362 
01363     return CS_SUCCEED;
01364 }
01365 
01366 
01367 void CTLibContext::SetClientCharset(const string& charset)
01368 {
01369     impl::CDriverContext::SetClientCharset(charset);
01370 
01371     if ( !GetClientCharset().empty() ) {
01372         CMutexGuard mg(s_CTLCtxMtx);
01373 
01374         cs_locale(CTLIB_GetContext(),
01375                   CS_SET,
01376                   m_Locale,
01377                   CS_SYB_CHARSET,
01378                   (CS_CHAR*) GetClientCharset().c_str(),
01379                   CS_NULLTERM,
01380                   NULL);
01381     }
01382 }
01383 
01384 // Tunable version of TDS protocol to use
01385 
01386 #if !defined(NCBI_CTLIB_TDS_VERSION)
01387 #    define NCBI_CTLIB_TDS_VERSION 125
01388 #endif
01389 
01390 #define NCBI_CTLIB_TDS_FALLBACK_VERSION 110
01391 
01392 
01393 NCBI_PARAM_DECL  (int, ctlib, TDS_VERSION);
01394 NCBI_PARAM_DEF_EX(int, ctlib, TDS_VERSION,
01395                   NCBI_CTLIB_TDS_VERSION,  // default TDS version
01396                   eParam_NoThread,
01397                   CTLIB_TDS_VERSION);
01398 typedef NCBI_PARAM_TYPE(ctlib, TDS_VERSION) TCtlibTdsVersion;
01399 
01400 
01401 #ifdef FTDS_IN_USE
01402 # define FTDS_VERSION_ERR_LEVEL Info
01403 #else
01404 # define FTDS_VERSION_ERR_LEVEL Warning
01405 #endif
01406 
01407 CS_INT GetCtlibTdsVersion(int version)
01408 {
01409     if (version == 0) {
01410 #ifdef FTDS_IN_USE
01411         return version;
01412 #else
01413         version = TCtlibTdsVersion::GetDefault();
01414 #endif
01415     }
01416 
01417     switch ( version ) {
01418     case 42:
01419     case 46:
01420     case 70:
01421     case 80:
01422         return version;
01423     case 100:
01424         return CS_VERSION_100;
01425     case 110:
01426         return CS_VERSION_110;
01427 #ifdef CS_VERSION_120
01428     case 120:
01429         return CS_VERSION_120;
01430 #endif
01431 #ifdef CS_VERSION_125
01432     case 125:
01433         return CS_VERSION_125;
01434 #endif
01435     }
01436 
01437     int fallback_version = (version == NCBI_CTLIB_TDS_VERSION) ?
01438         NCBI_CTLIB_TDS_FALLBACK_VERSION : NCBI_CTLIB_TDS_VERSION;
01439 
01440     ERR_POST_X(5, FTDS_VERSION_ERR_LEVEL
01441                << "The version " << version << " of TDS protocol for "
01442                "the DBAPI CTLib driver is not supported. Falling back to "
01443                "the TDS protocol version " << fallback_version << ".");
01444 
01445     return GetCtlibTdsVersion(fallback_version);
01446 }
01447 
01448 
01449 
01450 ///////////////////////////////////////////////////////////////////////
01451 // Driver manager related functions
01452 //
01453 
01454 ///////////////////////////////////////////////////////////////////////////////
01455 class CDbapiCtlibCFBase : public CSimpleClassFactoryImpl<I_DriverContext, CTLibContext>
01456 {
01457 public:
01458     typedef CSimpleClassFactoryImpl<I_DriverContext, CTLibContext> TParent;
01459 
01460 public:
01461     CDbapiCtlibCFBase(const string& driver_name);
01462     ~CDbapiCtlibCFBase(void);
01463 
01464 public:
01465     virtual TInterface*
01466     CreateInstance(
01467         const string& driver  = kEmptyStr,
01468         CVersionInfo version =
01469         NCBI_INTERFACE_VERSION(I_DriverContext),
01470         const TPluginManagerParamTree* params = 0) const;
01471 
01472 };
01473 
01474 CDbapiCtlibCFBase::CDbapiCtlibCFBase(const string& driver_name)
01475     : TParent( driver_name, 0 )
01476 {
01477     return ;
01478 }
01479 
01480 CDbapiCtlibCFBase::~CDbapiCtlibCFBase(void)
01481 {
01482     return ;
01483 }
01484 
01485 CDbapiCtlibCFBase::TInterface*
01486 CDbapiCtlibCFBase::CreateInstance(
01487     const string& driver,
01488     CVersionInfo version,
01489     const TPluginManagerParamTree* params) const
01490 {
01491     auto_ptr<TImplementation> drv;
01492 
01493     if ( !driver.empty()  &&  driver != m_DriverName ) {
01494         return 0;
01495     }
01496 
01497     if (version.Match(NCBI_INTERFACE_VERSION(I_DriverContext))
01498                         != CVersionInfo::eNonCompatible) {
01499 
01500         // Mandatory parameters ....
01501 #ifdef FTDS_IN_USE
01502         bool reuse_context = false; // Be careful !!!
01503         int  tds_version   = 0;
01504 #else
01505         // Previous behahviour was: reuse_context = true
01506         bool reuse_context = false;
01507         int  tds_version   = NCBI_CTLIB_TDS_VERSION;
01508 #endif
01509 
01510         // Optional parameters ...
01511         CS_INT page_size = 0;
01512         string prog_name;
01513         string host_name;
01514         string client_charset;
01515         unsigned int max_connect = 0;
01516 
01517         if ( params != NULL ) {
01518             typedef TPluginManagerParamTree::TNodeList_CI TCIter;
01519             typedef TPluginManagerParamTree::TValueType   TValue;
01520 
01521             // Get parameters ...
01522             TCIter cit  = params->SubNodeBegin();
01523             TCIter cend = params->SubNodeEnd();
01524 
01525             for (; cit != cend; ++cit) {
01526                 const TValue& v = (*cit)->GetValue();
01527 
01528                 if ( v.id == "reuse_context" ) {
01529                     reuse_context = (v.value != "false");
01530                 } else if ( v.id == "version" ) {
01531                     tds_version = NStr::StringToInt(v.value);
01532                     _TRACE("WARNING: user manually set TDS version to " << tds_version);
01533                 } else if ( v.id == "packet" ) {
01534                     page_size = NStr::StringToInt(v.value);
01535                 } else if ( v.id == "prog_name" ) {
01536                     prog_name = v.value;
01537                 } else if ( v.id == "host_name" ) {
01538                     host_name = v.value;
01539                 } else if ( v.id == "client_charset" ) {
01540                     client_charset = v.value;
01541                 } else if ( v.id == "max_connect" ) {
01542                     max_connect = NStr::StringToInt(v.value);;
01543                 }
01544             }
01545         }
01546 
01547         // Create a driver ...
01548         drv.reset(new CTLibContext(reuse_context,
01549                                    GetCtlibTdsVersion(tds_version)
01550                                    )
01551                   );
01552 
01553         // Set parameters ...
01554         if (page_size) {
01555             drv->CTLIB_SetPacketSize(page_size);
01556         }
01557 
01558         if (!prog_name.empty()) {
01559             drv->SetApplicationName(prog_name);
01560         }
01561 
01562         if (!host_name.empty()) {
01563             drv->SetHostName(host_name);
01564         }
01565 
01566         if (!client_charset.empty()) {
01567             drv->SetClientCharset(client_charset);
01568         }
01569 
01570         if (max_connect && CDbapiConnMgr::Instance().GetMaxConnect() < max_connect) {
01571             CDbapiConnMgr::Instance().SetMaxConnect(max_connect);
01572         }
01573         drv->SetMaxConnect(1000);
01574     }
01575 
01576     return drv.release();
01577 }
01578 
01579 ///////////////////////////////////////////////////////////////////////////////
01580 #if defined(FTDS_IN_USE)
01581 
01582 class CDbapiCtlibCF_ftds64_ctlib : public CDbapiCtlibCFBase
01583 {
01584 public:
01585     CDbapiCtlibCF_ftds64_ctlib(void)
01586     : CDbapiCtlibCFBase("ftds64")
01587     {
01588     }
01589 };
01590 
01591 
01592 class CDbapiCtlibCF_ftds : public CDbapiCtlibCFBase
01593 {
01594 public:
01595     CDbapiCtlibCF_ftds(void)
01596     : CDbapiCtlibCFBase("ftds")
01597     {
01598     }
01599 };
01600 
01601 #else
01602 
01603 class CDbapiCtlibCF_Sybase : public CDbapiCtlibCFBase
01604 {
01605 public:
01606     CDbapiCtlibCF_Sybase(void)
01607     : CDbapiCtlibCFBase("ctlib")
01608     {
01609     }
01610 };
01611 
01612 #endif
01613 
01614 
01615 #ifdef FTDS_IN_USE
01616 } // namespace ftds64_ctlib
01617 #endif
01618 
01619 
01620 ///////////////////////////////////////////////////////////////////////////////
01621 #if defined(FTDS_IN_USE)
01622 
01623 void
01624 NCBI_EntryPoint_xdbapi_ftds64(
01625     CPluginManager<I_DriverContext>::TDriverInfoList&   info_list,
01626     CPluginManager<I_DriverContext>::EEntryPointRequest method)
01627 {
01628     CHostEntryPointImpl<ftds64_ctlib::CDbapiCtlibCF_ftds64_ctlib>::NCBI_EntryPointImpl( info_list, method );
01629 }
01630 
01631 void
01632 NCBI_EntryPoint_xdbapi_ftds(
01633     CPluginManager<I_DriverContext>::TDriverInfoList&   info_list,
01634     CPluginManager<I_DriverContext>::EEntryPointRequest method)
01635 {
01636     CHostEntryPointImpl<ftds64_ctlib::CDbapiCtlibCF_ftds>::NCBI_EntryPointImpl(
01637         info_list,
01638         method
01639         );
01640 }
01641 
01642 
01643 void
01644 DBAPI_RegisterDriver_FTDS(void)
01645 {
01646     RegisterEntryPoint<I_DriverContext>(NCBI_EntryPoint_xdbapi_ftds);
01647     RegisterEntryPoint<I_DriverContext>(NCBI_EntryPoint_xdbapi_ftds64);
01648 }
01649 
01650 
01651 #else // defined(FTDS_IN_USE)
01652 
01653 void
01654 NCBI_EntryPoint_xdbapi_ctlib(
01655     CPluginManager<I_DriverContext>::TDriverInfoList&   info_list,
01656     CPluginManager<I_DriverContext>::EEntryPointRequest method)
01657 {
01658     CHostEntryPointImpl<CDbapiCtlibCF_Sybase>::NCBI_EntryPointImpl( info_list, method );
01659 }
01660 
01661 
01662 void
01663 DBAPI_RegisterDriver_CTLIB(void)
01664 {
01665     RegisterEntryPoint<I_DriverContext>( NCBI_EntryPoint_xdbapi_ctlib );
01666 }
01667 
01668 
01669 #endif // defined(FTDS_IN_USE)
01670 
01671 END_NCBI_SCOPE
01672 
01673 
01674 
01675 

Generated on Wed Mar 11 19:55:44 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Mar 11 23:15:42 2009 by modify_doxy.py rev. 117643