00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
00085
00086
00087
00088
00089
00090 DEFINE_STATIC_MUTEX(s_CTLCtxMtx);
00091
00092
00093
00094
00095
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
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
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
00234 Close();
00235 Drop();
00236 }
00237 NCBI_CATCH_ALL_X( 7, NCBI_CURRENT_FUNCTION )
00238 }
00239
00240
00241 bool Connection::Drop(void)
00242 {
00243
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 }
00529
00530
00531
00532
00533
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
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
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
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
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
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
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
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
00894
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
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
01117 }
01118 else {
01119 if (msg->severity != CS_SV_INFORM) {
01120 ostrstream err_str;
01121
01122
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
01145
01146
01147
01148
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
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
01232
01233
01234 msg->msgnumber == 3621 ||
01235 msg->msgnumber == 3980 ||
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
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 ) {
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
01313
01314
01315
01316
01317
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
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,
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
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
01501 #ifdef FTDS_IN_USE
01502 bool reuse_context = false;
01503 int tds_version = 0;
01504 #else
01505
01506 bool reuse_context = false;
01507 int tds_version = NCBI_CTLIB_TDS_VERSION;
01508 #endif
01509
01510
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
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
01548 drv.reset(new CTLibContext(reuse_context,
01549 GetCtlibTdsVersion(tds_version)
01550 )
01551 );
01552
01553
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 }
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