1 /* $Id: dbapi_conn_factory.cpp 630683 2021-05-06 15:49:27Z ivanov $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Sergey Sikorskiy, Aaron Ucko
27 *
28 */
29
30 #include <ncbi_pch.hpp>
31
32 #include <dbapi/driver/dbapi_conn_factory.hpp>
33 #include <dbapi/driver/dbapi_svc_mapper.hpp>
34 #include <dbapi/driver/dbapi_driver_conn_params.hpp>
35 #include <dbapi/driver/impl/dbapi_driver_utils.hpp>
36 #include <dbapi/driver/impl/dbapi_impl_connection.hpp>
37 #include <dbapi/driver/impl/dbapi_impl_context.hpp>
38 #include <dbapi/driver/impl/dbapi_pool_balancer.hpp>
39 #include <dbapi/driver/public.hpp>
40 #include <dbapi/error_codes.hpp>
41 #include <corelib/ncbiapp.hpp>
42 #include <corelib/request_ctx.hpp>
43
44 #include <list>
45
46
47 #define NCBI_USE_ERRCODE_X Dbapi_ConnFactory
48
49 BEGIN_NCBI_SCOPE
50
51
52 ///////////////////////////////////////////////////////////////////////////////
CDBConnectionFactory(IDBServiceMapper::TFactory svc_mapper_factory,const IRegistry * registry,EDefaultMapping def_mapping)53 CDBConnectionFactory::CDBConnectionFactory(IDBServiceMapper::TFactory svc_mapper_factory,
54 const IRegistry* registry,
55 EDefaultMapping def_mapping) :
56 m_MapperFactory(svc_mapper_factory, registry, def_mapping),
57 m_MaxNumOfConnAttempts(1),
58 m_MaxNumOfValidationAttempts(1),
59 m_MaxNumOfServerAlternatives(32),
60 m_MaxNumOfDispatches(0),
61 m_ConnectionTimeout(0),
62 m_LoginTimeout(0),
63 m_TryServerToo(false)
64 {
65 ConfigureFromRegistry(registry);
66 }
67
~CDBConnectionFactory(void)68 CDBConnectionFactory::~CDBConnectionFactory(void)
69 {
70 CDB_UserHandler::ClearExceptions(m_Errors);
71 }
72
73 void
ConfigureFromRegistry(const IRegistry * registry)74 CDBConnectionFactory::ConfigureFromRegistry(const IRegistry* registry)
75 {
76 const string section_name("DB_CONNECTION_FACTORY");
77
78 // Get current registry ...
79 if (!registry && CNcbiApplication::Instance()) {
80 registry = &CNcbiApplication::Instance()->GetConfig();
81 }
82
83 if (registry) {
84 m_MaxNumOfConnAttempts =
85 registry->GetInt(section_name, "MAX_CONN_ATTEMPTS", 1);
86 m_MaxNumOfValidationAttempts =
87 registry->GetInt(section_name, "MAX_VALIDATION_ATTEMPTS", 1);
88 m_MaxNumOfServerAlternatives =
89 registry->GetInt(section_name, "MAX_SERVER_ALTERNATIVES", 32);
90 m_MaxNumOfDispatches =
91 registry->GetInt(section_name, "MAX_DISPATCHES", 0);
92 m_ConnectionTimeout =
93 registry->GetInt(section_name, "CONNECTION_TIMEOUT", 0);
94 m_LoginTimeout =
95 registry->GetInt(section_name, "LOGIN_TIMEOUT", 0);
96 m_TryServerToo =
97 registry->GetBool(section_name, "TRY_SERVER_AFTER_SERVICE", false);
98 } else {
99 m_MaxNumOfConnAttempts = 1;
100 m_MaxNumOfValidationAttempts = 1;
101 m_MaxNumOfServerAlternatives = 32;
102 m_MaxNumOfDispatches = 0;
103 m_ConnectionTimeout = 0;
104 m_LoginTimeout = 0;
105 m_TryServerToo = false;
106 }
107 }
108
109 void
Configure(const IRegistry * registry)110 CDBConnectionFactory::Configure(const IRegistry* registry)
111 {
112 CFastMutexGuard mg(m_Mtx);
113
114 ConfigureFromRegistry(registry);
115 }
116
117 void
SetMaxNumOfConnAttempts(unsigned int max_num)118 CDBConnectionFactory::SetMaxNumOfConnAttempts(unsigned int max_num)
119 {
120 CFastMutexGuard mg(m_Mtx);
121
122 m_MaxNumOfConnAttempts = max_num;
123 }
124
125 void
SetMaxNumOfValidationAttempts(unsigned int max_num)126 CDBConnectionFactory::SetMaxNumOfValidationAttempts(unsigned int max_num)
127 {
128 CFastMutexGuard mg(m_Mtx);
129
130 m_MaxNumOfValidationAttempts = max_num;
131 }
132
133 void
SetMaxNumOfServerAlternatives(unsigned int max_num)134 CDBConnectionFactory::SetMaxNumOfServerAlternatives(unsigned int max_num)
135 {
136 CFastMutexGuard mg(m_Mtx);
137
138 m_MaxNumOfServerAlternatives = max_num;
139 }
140
141 void
SetMaxNumOfDispatches(unsigned int max_num)142 CDBConnectionFactory::SetMaxNumOfDispatches(unsigned int max_num)
143 {
144 CFastMutexGuard mg(m_Mtx);
145
146 m_MaxNumOfDispatches = max_num;
147 }
148
149 void
SetConnectionTimeout(unsigned int timeout)150 CDBConnectionFactory::SetConnectionTimeout(unsigned int timeout)
151 {
152 CFastMutexGuard mg(m_Mtx);
153
154 m_ConnectionTimeout = timeout;
155 }
156
157 void
SetLoginTimeout(unsigned int timeout)158 CDBConnectionFactory::SetLoginTimeout(unsigned int timeout)
159 {
160 CFastMutexGuard mg(m_Mtx);
161
162 m_LoginTimeout = timeout;
163 }
164
165 unsigned int
CalculateConnectionTimeout(const I_DriverContext & ctx) const166 CDBConnectionFactory::CalculateConnectionTimeout
167 (const I_DriverContext& ctx) const
168 {
169 unsigned int timeout = 30;
170
171 unsigned int to = GetConnectionTimeout();
172 if (to != 0) {
173 timeout = to;
174 }
175 else {
176 to = ctx.GetTimeout();
177 if (to != 0) {
178 timeout = to;
179 }
180 }
181
182 return timeout;
183 }
184
185 unsigned int
CalculateLoginTimeout(const I_DriverContext & ctx) const186 CDBConnectionFactory::CalculateLoginTimeout(const I_DriverContext& ctx) const
187 {
188 unsigned int timeout = 30;
189
190 unsigned int to = GetLoginTimeout();
191 if (to != 0) {
192 timeout = to;
193 }
194 else {
195 to = ctx.GetLoginTimeout();
196 if (to != 0) {
197 timeout = to;
198 }
199 }
200
201 return timeout;
202 }
203
204 CDBConnectionFactory::CRuntimeData&
GetRuntimeData(const CRef<IConnValidator> validator)205 CDBConnectionFactory::GetRuntimeData(const CRef<IConnValidator> validator)
206 {
207 string validator_name;
208 if (validator) {
209 validator_name = validator->GetName();
210 }
211 return GetRuntimeData(validator_name);
212 }
213
214 CDBConnectionFactory::CRuntimeData&
GetRuntimeData(const string & validator_name)215 CDBConnectionFactory::GetRuntimeData(const string& validator_name)
216 {
217 TValidatorSet::iterator it = m_ValidatorSet.find(validator_name);
218 if (it != m_ValidatorSet.end()) {
219 return it->second;
220 }
221
222 return m_ValidatorSet.insert(TValidatorSet::value_type(
223 validator_name,
224 CRuntimeData(*this, CRef<IDBServiceMapper>(m_MapperFactory.Make()))
225 )).first->second;
226 }
227
228
229 ///////////////////////////////////////////////////////////////////////////////
230 class CDB_DBLB_Delegate : public CDBConnParamsDelegate
231 {
232 public:
233 CDB_DBLB_Delegate(
234 const string& srv_name,
235 Uint4 host,
236 Uint2 port,
237 const CDBConnParams& other);
238 virtual ~CDB_DBLB_Delegate(void);
239
240 public:
241 virtual string GetServerName(void) const;
242 virtual Uint4 GetHost(void) const;
243 virtual Uint2 GetPort(void) const;
244 virtual const impl::CDBHandlerStack& GetOpeningMsgHandlers(void) const;
245 impl::CDBHandlerStack& SetOpeningMsgHandlers(void);
246
247 private:
248 // Non-copyable.
249 CDB_DBLB_Delegate(const CDB_DBLB_Delegate& other);
250 CDB_DBLB_Delegate& operator =(const CDB_DBLB_Delegate& other);
251
252 private:
253 const string m_ServerName;
254 const Uint4 m_Host;
255 const Uint2 m_Port;
256 impl::CDBHandlerStack m_OpeningMsgHandlers;
257 };
258
259
CDB_DBLB_Delegate(const string & srv_name,Uint4 host,Uint2 port,const CDBConnParams & other)260 CDB_DBLB_Delegate::CDB_DBLB_Delegate(
261 const string& srv_name,
262 Uint4 host,
263 Uint2 port,
264 const CDBConnParams& other)
265 : CDBConnParamsDelegate(other)
266 , m_ServerName(srv_name)
267 , m_Host(host)
268 , m_Port(port)
269 {
270 }
271
~CDB_DBLB_Delegate(void)272 CDB_DBLB_Delegate::~CDB_DBLB_Delegate(void)
273 {
274 }
275
276
GetServerName(void) const277 string CDB_DBLB_Delegate::GetServerName(void) const
278 {
279 return m_ServerName;
280 }
281
282
GetHost(void) const283 Uint4 CDB_DBLB_Delegate::GetHost(void) const
284 {
285 return m_Host;
286 }
287
288
GetPort(void) const289 Uint2 CDB_DBLB_Delegate::GetPort(void) const
290 {
291 return m_Port;
292 }
293
GetOpeningMsgHandlers(void) const294 const impl::CDBHandlerStack& CDB_DBLB_Delegate::GetOpeningMsgHandlers(void)
295 const
296 {
297 return m_OpeningMsgHandlers;
298 }
299
SetOpeningMsgHandlers(void)300 impl::CDBHandlerStack& CDB_DBLB_Delegate::SetOpeningMsgHandlers(void)
301 {
302 return m_OpeningMsgHandlers;
303 }
304
305 ///////////////////////////////////////////////////////////////////////////////
SOpeningContext(I_DriverContext & driver_ctx_in)306 CDBConnectionFactory::SOpeningContext::SOpeningContext
307 (I_DriverContext& driver_ctx_in)
308 : driver_ctx(driver_ctx_in), conn_status(IConnValidator::eInvalidConn)
309 {
310 }
311
312 CDB_Connection*
MakeDBConnection(I_DriverContext & ctx,const CDBConnParams & params)313 CDBConnectionFactory::MakeDBConnection(
314 I_DriverContext& ctx,
315 const CDBConnParams& params)
316 {
317 CFastMutexGuard mg(m_Mtx);
318
319 CDB_UserHandler::ClearExceptions(m_Errors);
320
321 unique_ptr<CDB_Connection> t_con;
322 CRuntimeData& rt_data = GetRuntimeData(params.GetConnValidator());
323 TSvrRef dsp_srv = rt_data.GetDispatchedServer(params.GetServerName());
324
325 // Prepare to collect messages, whose proper severity depends on whether
326 // ANY attempt succeeds.
327 impl::CDBHandlerStack ultimate_handlers;
328 {{
329 const impl::CDriverContext* ctx_impl
330 = dynamic_cast<impl::CDriverContext*>(&ctx);
331 if (params.GetOpeningMsgHandlers().GetSize() > 0) {
332 ultimate_handlers = params.GetOpeningMsgHandlers();
333 } else if (ctx_impl != NULL) {
334 ultimate_handlers = ctx_impl->GetCtxHandlerStack();
335 } else {
336 ultimate_handlers.Push(&CDB_UserHandler::GetDefault());
337 }
338 }}
339 SOpeningContext opening_ctx(ctx);
340 CRef<CDB_UserHandler_Deferred> handler
341 (new CDB_UserHandler_Deferred(ultimate_handlers));
342 opening_ctx.handlers.Push(&*handler, eTakeOwnership);
343
344 // Store original query timeout ...
345 unsigned int query_timeout = ctx.GetTimeout();
346
347 // Set "validation timeouts" ...
348 ctx.SetTimeout(CalculateConnectionTimeout(ctx));
349 ctx.SetLoginTimeout(CalculateLoginTimeout(ctx));
350
351 if ( dsp_srv.Empty() ) {
352 // We are here either because server name was never dispatched or
353 // because a named connection pool has been used before.
354 // Dispatch server name ...
355
356 t_con.reset(DispatchServerName(opening_ctx, params));
357 } else {
358 // Server name is already dispatched ...
359 string single_server(params.GetParam("single_server"));
360 string is_pooled(params.GetParam("is_pooled"));
361
362 // We probably need to re-dispatch it ...
363 if (single_server != "true"
364 && ((GetMaxNumOfDispatches()
365 && (rt_data.GetNumOfDispatches(params.GetServerName())
366 >= GetMaxNumOfDispatches()))
367 || (dsp_srv->GetExpireTime() != 0
368 && (CurrentTime(CTime::eUTC).GetTimeT()
369 > dsp_srv->GetExpireTime())))) {
370 // We definitely need to re-dispatch it ...
371
372 // Clean previous info ...
373 rt_data.CleanExcluded(params.GetServerName());
374 rt_data.SetDispatchedServer(params.GetServerName(), TSvrRef());
375 if (is_pooled == "true") {
376 rt_data.GetServerOptions(params.GetServerName()).clear();
377 }
378 t_con.reset(DispatchServerName(opening_ctx, params));
379 } else if (single_server != "true" && is_pooled == "true") {
380 // Don't fully redispatch, but keep the pool balanced
381 t_con.reset(DispatchServerName(opening_ctx, params));
382 } else {
383 // We do not need to re-dispatch it ...
384
385 // Try to connect.
386 try {
387 opening_ctx.last_tried.Reset(dsp_srv); // provisionally
388 // I_DriverContext::SConnAttr cur_conn_attr(conn_attr);
389 // cur_conn_attr.srv_name = dsp_srv->GetName();
390 CDB_DBLB_Delegate cur_params(
391 dsp_srv->GetName(),
392 dsp_srv->GetHost(),
393 dsp_srv->GetPort(),
394 params);
395 cur_params.SetOpeningMsgHandlers() = opening_ctx.handlers;
396
397 // MakeValidConnection may return NULL here because a newly
398 // created connection may not pass validation.
399 t_con.reset(MakeValidConnection(opening_ctx,
400 // cur_conn_attr,
401 cur_params));
402
403 } catch (CDB_Exception& ex) {
404 // m_Errors.push_back(ex.Clone());
405 opening_ctx.handlers.PostMsg(&ex);
406 if (params.GetConnValidator()) {
407 opening_ctx.conn_status
408 = params.GetConnValidator()->ValidateException(ex);
409 }
410 }
411
412 if (t_con.get() == NULL) {
413 // We couldn't connect ...
414 if (single_server != "true") {
415 // Server might be temporarily unavailable ...
416 // Check conn_status ...
417 if (opening_ctx.conn_status
418 == IConnValidator::eTempInvalidConn) {
419 rt_data.IncNumOfValidationFailures
420 (params.GetServerName(), opening_ctx.last_tried);
421 }
422
423 // Re-dispatch ...
424 t_con.reset(DispatchServerName(opening_ctx, params));
425 }
426 } else {
427 // Dispatched server is already set, but calling of this method
428 // will increase number of successful dispatches.
429 rt_data.SetDispatchedServer(params.GetServerName(),
430 opening_ctx.last_tried);
431 }
432 }
433 }
434
435 // Restore original connection timeout ...
436 ctx.SetTimeout(query_timeout);
437
438 // Restore original query timeout ...
439 if (t_con.get() != NULL) {
440 t_con->SetTimeout(query_timeout);
441 }
442
443 x_LogConnection(opening_ctx, t_con.get(), params);
444 handler->Flush((t_con.get() == NULL) ? eDiagSevMax : eDiag_Warning);
445
446 return t_con.release();
447 }
448
449 CDB_Connection*
DispatchServerName(SOpeningContext & ctx,const CDBConnParams & params)450 CDBConnectionFactory::DispatchServerName(
451 SOpeningContext& ctx,
452 const CDBConnParams& params)
453 {
454 CStopWatchScope timing(ctx.dispatch_server_name_sw);
455 CDB_Connection* t_con = NULL;
456 // I_DriverContext::SConnAttr curr_conn_attr(conn_attr);
457 const string service_name(params.GetServerName());
458 bool do_not_dispatch = params.GetParam("do_not_dispatch") == "true";
459 string cur_srv_name;
460 Uint4 cur_host = 0;
461 Uint2 cur_port = 0;
462
463 CRuntimeData& rt_data = GetRuntimeData(params.GetConnValidator());
464
465 // Try to connect up to a given number of alternative servers ...
466 unsigned int alternatives = GetMaxNumOfServerAlternatives();
467 list<TSvrRef> tried_servers;
468 bool full_retry_made = false;
469 CRef<CDBPoolBalancer> balancer;
470
471 if ( !do_not_dispatch && params.GetParam("is_pooled") == "true"
472 && !service_name.empty() ) {
473 balancer.Reset(new CDBPoolBalancer
474 (service_name, params.GetParam("pool_name"),
475 rt_data.GetServerOptions(service_name),
476 &ctx.driver_ctx));
477 }
478 for ( ; !t_con && alternatives > 0; --alternatives ) {
479 TSvrRef dsp_srv;
480
481 if (do_not_dispatch) {
482 cur_srv_name = params.GetServerName();
483 cur_host = params.GetHost();
484 cur_port = params.GetPort();
485 }
486 // It is possible that a server name won't be provided.
487 // This is possible when somebody uses a named connection pool.
488 // In this case we even won't try to map it.
489 else if (!service_name.empty()) {
490 if (balancer.NotEmpty()) {
491 dsp_srv = balancer->GetServer(&t_con, ¶ms);
492 }
493 if (dsp_srv.Empty()) {
494 dsp_srv = rt_data.GetDispatchedServer(service_name);
495 }
496 if (dsp_srv.Empty()) {
497 dsp_srv = rt_data.GetDBServiceMapper().GetServer(service_name);
498 }
499
500 if (tried_servers.empty()
501 && (dsp_srv.Empty()
502 || (dsp_srv->GetName() == service_name
503 && dsp_srv->GetHost() == 0
504 && dsp_srv->GetPort() == 0
505 && !rt_data.GetExcluded(service_name).empty() ))) {
506 _TRACE("List of servers for service " << service_name
507 << " is exhausted. Giving excluded a try.");
508 rt_data.CleanExcluded(service_name);
509 dsp_srv = rt_data.GetDBServiceMapper().GetServer(service_name);
510 }
511
512 if (dsp_srv.Empty()) {
513 m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0),
514 "Service mapper didn't return any server for " + service_name, eDiag_Error, 0));
515 return NULL;
516 }
517 if (dsp_srv->GetName() == service_name
518 && dsp_srv->GetHost() == 0 && dsp_srv->GetPort() == 0
519 && !tried_servers.empty())
520 {
521 if (full_retry_made) {
522 if (!m_TryServerToo) {
523 m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0),
524 "No more servers to try (didn't try " + service_name + " as server name)", eDiag_Error, 0));
525 return NULL;
526 }
527 }
528 else {
529 _TRACE("List of servers for service " << service_name
530 << " is exhausted. Giving excluded a try.");
531
532 rt_data.CleanExcluded(service_name);
533 ITERATE(list<TSvrRef>, it, tried_servers) {
534 rt_data.Exclude(service_name, *it);
535 }
536 if (balancer.NotEmpty()) {
537 balancer.Reset
538 (new CDBPoolBalancer
539 (service_name, params.GetParam("pool_name"),
540 rt_data.GetServerOptions(service_name, true),
541 &ctx.driver_ctx));
542 }
543 full_retry_made = true;
544 continue;
545 }
546 }
547
548 // If connection attempts will take too long mapper can return
549 // the same server once more. Let's not try to connect to it
550 // again.
551 bool found = false;
552 ITERATE(list<TSvrRef>, it, tried_servers) {
553 if (**it == *dsp_srv) {
554 rt_data.Exclude(service_name, dsp_srv);
555 found = true;
556 break;
557 }
558 }
559 if (found)
560 continue;
561
562 // curr_conn_attr.srv_name = dsp_srv->GetName();
563 cur_srv_name = dsp_srv->GetName();
564 cur_host = dsp_srv->GetHost();
565 cur_port = dsp_srv->GetPort();
566 } else if (params.GetParam("pool_name").empty()) {
567 DATABASE_DRIVER_ERROR
568 ("Neither server name nor pool name provided.", 111000);
569 } else {
570 // Old-fashioned connection pool.
571 // We do not change anything ...
572 cur_srv_name = params.GetServerName();
573 cur_host = params.GetHost();
574 cur_port = params.GetPort();
575 }
576
577 // Try to connect up to a given number of attempts ...
578 unsigned int attempts = GetMaxNumOfConnAttempts();
579 bool need_exclude = true;
580 ctx.conn_status = IConnValidator::eInvalidConn;
581
582 // We don't check value of conn_status inside of a loop below by design.
583 for (; attempts > 0; --attempts) {
584 try {
585 CDB_DBLB_Delegate cur_params(
586 cur_srv_name,
587 cur_host,
588 cur_port,
589 params);
590 cur_params.SetOpeningMsgHandlers() = ctx.handlers;
591 t_con = MakeValidConnection(ctx,
592 // curr_conn_attr,
593 cur_params,
594 t_con);
595 if (t_con != NULL) {
596 need_exclude = false;
597 break;
598 }
599 } catch (CDB_Exception& ex) {
600 // m_Errors.push_back(ex.Clone());
601 ctx.handlers.PostMsg(&ex);
602 if (params.GetConnValidator()) {
603 ctx.conn_status
604 = params.GetConnValidator()->ValidateException(ex);
605 }
606 if (ex.GetDBErrCode() == 200011) { // pool full
607 need_exclude = false;
608 }
609 }
610 }
611
612 if (do_not_dispatch) {
613 return t_con;
614 }
615 else if (!t_con) {
616 if (cur_srv_name == service_name && cur_host == 0 && cur_port == 0
617 && (ctx.conn_status != IConnValidator::eTempInvalidConn
618 || (GetMaxNumOfValidationAttempts()
619 && rt_data.GetNumOfValidationFailures(service_name)
620 >= GetMaxNumOfValidationAttempts())))
621 {
622 m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0),
623 "No more services/servers to try", eDiag_Error, 0));
624 return NULL;
625 }
626
627 if (need_exclude) {
628 // Server might be temporarily unavailable ...
629 // Check conn_status ...
630 if (ctx.conn_status == IConnValidator::eTempInvalidConn) {
631 rt_data.IncNumOfValidationFailures(service_name,
632 ctx.last_tried);
633 } else {
634 // conn_status == IConnValidator::eInvalidConn
635 rt_data.Exclude(service_name, ctx.last_tried);
636 tried_servers.push_back(ctx.last_tried);
637 }
638 }
639 } else {
640 rt_data.SetDispatchedServer(service_name, dsp_srv);
641 }
642 }
643
644 if (!t_con) {
645 m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0),
646 "Can't try any more alternatives (max number is "
647 + NStr::UIntToString(GetMaxNumOfServerAlternatives()) + ")", eDiag_Error, 0));
648 }
649 return t_con;
650 }
651
652 CDB_Connection*
MakeValidConnection(SOpeningContext & ctx,const CDBConnParams & params,CDB_Connection * candidate)653 CDBConnectionFactory::MakeValidConnection(
654 SOpeningContext& ctx,
655 const CDBConnParams& params,
656 CDB_Connection* candidate)
657 {
658 CStopWatchScope timing(ctx.make_valid_connection_sw);
659 _TRACE("Trying to connect to server '" << params.GetServerName()
660 << "', host " << impl::ConvertN2A(params.GetHost())
661 << ", port " << params.GetPort());
662 if (params.GetHost() != 0) {
663 ctx.tried.push_back(impl::ConvertN2A(params.GetHost()) + ':'
664 + NStr::NumericToString(params.GetPort()));
665 } else {
666 ctx.tried.push_back(params.GetServerName());
667 }
668
669 unique_ptr<CDB_Connection> conn;
670 try {
671 if (candidate == NULL) {
672 conn.reset(CtxMakeConnection(ctx.driver_ctx, params));
673 } else {
674 conn.reset(candidate);
675 }
676 } catch (...) {
677 CRef<IConnValidator> validator = params.GetConnValidator();
678 CRuntimeData& rt_data = GetRuntimeData(validator);
679 const string& service = params.GetServerName();
680 ctx.last_tried.Reset(rt_data.GetDispatchedServer(service));
681 if (ctx.last_tried.Empty()) {
682 ctx.last_tried.Reset
683 (new CDBServer(service, params.GetHost(), params.GetPort()));
684 }
685 throw;
686 }
687
688 if (conn.get())
689 {
690 ctx.last_tried.Reset(new CDBServer(conn->ServerName(),
691 conn->Host(), conn->Port()));
692 if (conn->IsReusable() && !params.GetParam("pool_name").empty()) {
693 if (conn->Host() != 0) {
694 ctx.tried.back() = (impl::ConvertN2A(conn->Host()) + ':'
695 + NStr::NumericToString(conn->Port()));
696 } else {
697 ctx.tried.back() = conn->ServerName();
698 }
699 }
700
701 if (conn->Host() == 0) {
702 GetRuntimeData(params.GetConnValidator()).GetDBServiceMapper()
703 .RecordServer(conn->GetExtraFeatures());
704 }
705 CTrivialConnValidator use_db_validator(
706 params.GetDatabaseName(),
707 CTrivialConnValidator::eKeepModifiedConnection
708 );
709 CConnValidatorCoR validator;
710
711 validator.Push(params.GetConnValidator());
712
713 // Check "use <database>" command ...
714 if (!params.GetDatabaseName().empty()) {
715 validator.Push(CRef<IConnValidator>(&use_db_validator));
716 }
717
718 ctx.conn_status = IConnValidator::eInvalidConn;
719 try {
720 ctx.conn_status = validator.Validate(*conn);
721 if (ctx.conn_status != IConnValidator::eValidConn) {
722 if (conn->IsReusable()) {
723 static_cast<impl::CConnection&>(conn->GetExtraFeatures())
724 .m_Reusable = false;
725 }
726 CDB_Exception ex(DIAG_COMPILE_INFO, NULL,
727 CDB_Exception::EErrCode(0),
728 "Validation failed against "
729 + params.GetServerName(),
730 eDiag_Error, 0);
731 ex.SetRetriable(eRetriable_No);
732 // m_Errors.push_back(ex.Clone());
733 ctx.handlers.PostMsg(&ex);
734 return NULL;
735 }
736 } catch (CDB_Exception& ex) {
737 if (params.GetConnValidator().NotNull()) {
738 ctx.conn_status
739 = params.GetConnValidator()->ValidateException(ex);
740 }
741 if (ctx.conn_status != IConnValidator::eValidConn) {
742 if (conn->IsReusable()) {
743 static_cast<impl::CConnection&>(conn->GetExtraFeatures())
744 .m_Reusable = false;
745 }
746 // m_Errors.push_back(ex.Clone());
747 ctx.handlers.PostMsg(&ex);
748 return NULL;
749 }
750 } catch (const CException& ex) {
751 ERR_POST_X(1, Warning << ex.ReportAll() << " when trying to connect to "
752 << "server '" << params.GetServerName() << "' as user '"
753 << params.GetUserName() << "'");
754 return NULL;
755 } catch (...) {
756 ERR_POST_X(2, Warning << "Unknown exception when trying to connect to "
757 << "server '" << params.GetServerName() << "' as user '"
758 << params.GetUserName() << "'");
759 throw;
760 }
761 ctx.tried.pop_back();
762 conn->FinishOpening();
763 }
764 else {
765 CRef<IConnValidator> validator = params.GetConnValidator();
766 CRuntimeData& rt_data = GetRuntimeData(validator);
767 const string& service = params.GetServerName();
768 ctx.last_tried.Reset(rt_data.GetDispatchedServer(service));
769 if (ctx.last_tried.Empty()) {
770 ctx.last_tried.Reset
771 (new CDBServer(service, params.GetHost(), params.GetPort()));
772 }
773
774 m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0),
775 "Parameters prohibited creating connection", eDiag_Error, 0));
776 }
777 return conn.release();
778 }
779
780 CDB_UserHandler::TExceptions*
GetExceptions(void)781 CDBConnectionFactory::GetExceptions(void)
782 {
783 return &m_Errors;
784 }
785
786 void
GetServersList(const string & validator_name,const string & service_name,list<string> * serv_list)787 CDBConnectionFactory::GetServersList(const string& validator_name,
788 const string& service_name,
789 list<string>* serv_list)
790 {
791 CFastMutexGuard mg(m_Mtx);
792
793 const IDBServiceMapper& mapper
794 = GetRuntimeData(validator_name).GetDBServiceMapper();
795 mapper.GetServersList(service_name, serv_list);
796 }
797
798 void
WorkWithSingleServer(const string & validator_name,const string & service_name,const string & server)799 CDBConnectionFactory::WorkWithSingleServer(const string& validator_name,
800 const string& service_name,
801 const string& server)
802 {
803 CFastMutexGuard mg(m_Mtx);
804
805 CRuntimeData& rt_data = GetRuntimeData(validator_name);
806 TSvrRef svr(new CDBServer(server, 0, 0, numeric_limits<unsigned int>::max()));
807 rt_data.SetDispatchedServer(service_name, svr);
808 }
809
810 // Make an effort to give each request its own connection numbering.
811 // The resulting field names can still technically repeat if an
812 // application reuses request IDs or tampers with named properties.
813 // However, that concern appears to be purely theoretical, and any
814 // duplication that does manage to occur will have fairly minor
815 // consequences. In contrast, a global counter would cause trouble
816 // for log analyzers, and a map would either accumulate stale keys or
817 // risk duplication.
s_GetNextLogPrefix(void)818 static string s_GetNextLogPrefix(void)
819 {
820 CRequestContext& rctx = GetDiagContext().GetRequestContext();
821 string rid_str = NStr::NumericToString(rctx.GetRequestID());
822 if (rctx.GetProperty("_dbapi_last_rid") == rid_str) {
823 string connection_no
824 = NStr::UIntToString(
825 NStr::StringToUInt(rctx.GetProperty("_dbapi_connection_no"))
826 + 1U);
827 rctx.SetProperty("_dbapi_connection_no", connection_no);
828 return connection_no + ".dbapi_";
829 } else {
830 rctx.SetProperty("_dbapi_last_rid", rid_str);
831 rctx.SetProperty("_dbapi_connection_no", "1");
832 return "1.dbapi_";
833 }
834 }
835
x_LogConnection(const SOpeningContext & ctx,const CDB_Connection * connection,const CDBConnParams & params)836 void CDBConnectionFactory::x_LogConnection(const SOpeningContext& ctx,
837 const CDB_Connection* connection,
838 const CDBConnParams& params)
839 {
840 CDBServer stub_dsp_srv;
841
842 CRef<IConnValidator> validator = params.GetConnValidator();
843 CRuntimeData& rt_data = GetRuntimeData(validator);
844 const string& service = params.GetServerName();
845 TSvrRef dsp_srv = ctx.last_tried;
846
847 CDiagContext_Extra extra = GetDiagContext().Extra();
848 string prefix = s_GetNextLogPrefix();
849
850 if (dsp_srv.Empty()) {
851 // Try rt_data.GetDispatchedServer(service) first?
852 dsp_srv.Reset(&stub_dsp_srv);
853 }
854
855 {{
856 const char* status_str = "???";
857 switch (ctx.conn_status) {
858 case IConnValidator::eValidConn:
859 status_str = "valid";
860 break;
861 case IConnValidator::eInvalidConn:
862 status_str = "invalid";
863 break;
864 case IConnValidator::eTempInvalidConn:
865 status_str = "temporarily-invalid";
866 break;
867 }
868 extra.Print(prefix + "conn_status", status_str);
869 }}
870
871 extra.Print(prefix + "resource", service);
872
873 if ( !dsp_srv->GetName().empty() ) {
874 extra.Print(prefix + "server_name", dsp_srv->GetName());
875 } else if (connection != NULL && !connection->ServerName().empty()) {
876 extra.Print(prefix + "server_name", connection->ServerName());
877 }
878
879 if (dsp_srv->GetHost() != 0) {
880 extra.Print(prefix + "server_ip",
881 impl::ConvertN2A(dsp_srv->GetHost()));
882 } else if (params.GetHost() != 0) {
883 extra.Print(prefix + "server_ip", impl::ConvertN2A(params.GetHost()));
884 } else if (connection != NULL && connection->Host() != 0) {
885 extra.Print(prefix + "server_ip",
886 impl::ConvertN2A(connection->Host()));
887 }
888
889 if (dsp_srv->GetPort() != 0) {
890 extra.Print(prefix + "server_port", dsp_srv->GetPort());
891 } else if (params.GetPort() != 0) {
892 extra.Print(prefix + "server_port", params.GetPort());
893 } else if (connection != NULL && connection->Port() != 0) {
894 extra.Print(prefix + "server_port", connection->Port());
895 }
896
897 if ( !params.GetUserName().empty() ) {
898 extra.Print(prefix + "username", params.GetUserName());
899 }
900
901 if ( !params.GetDatabaseName().empty() ) {
902 extra.Print(prefix + "db_name", params.GetDatabaseName());
903 } else {
904 CTrivialConnValidator* tcv
905 = dynamic_cast<CTrivialConnValidator*>(validator.GetPointer());
906 if (tcv != NULL && !tcv->GetDBName().empty()) {
907 extra.Print(prefix + "db_name", tcv->GetDBName());
908 }
909 }
910
911 if (connection != NULL && !connection->PoolName().empty() ) {
912 extra.Print(prefix + "pool", connection->PoolName());
913 } else if ( !params.GetParam("pool_name").empty() ) {
914 extra.Print(prefix + "pool", params.GetParam("pool_name"));
915 }
916
917 if (validator.NotEmpty()) {
918 extra.Print(prefix + "validator", validator->GetName());
919 }
920
921 {{
922 string driver_name = ((connection == NULL)
923 ? ctx.driver_ctx.GetDriverName()
924 : connection->GetDriverName());
925 if ( !driver_name.empty() ) {
926 extra.Print(prefix + "driver", driver_name);
927 }
928 }}
929
930 extra.Print(prefix + "name_mapper",
931 rt_data.GetDBServiceMapper().GetName());
932
933 size_t retries = ctx.tried.size();
934 if (ctx.conn_status != IConnValidator::eValidConn) {
935 --retries;
936 }
937 extra.Print(prefix + "retries", retries);
938 if ( !ctx.tried.empty() ) {
939 extra.Print(prefix + "tried", NStr::Join(ctx.tried, " "));
940 }
941 const string& excluded = rt_data.GetExcluded(service);
942 if ( !excluded.empty() ) {
943 extra.Print(prefix + "excluded", excluded);
944 }
945 if (connection != NULL) {
946 extra.Print(prefix + "conn_reuse_count", connection->GetReuseCount());
947 }
948
949 double make_valid_connection_elapsed = ctx.make_valid_connection_sw.Elapsed();
950 if (make_valid_connection_elapsed != 0.0) {
951 extra.Print(prefix + "make_valid_connection_time",
952 make_valid_connection_elapsed);
953 }
954
955 double dispatch_server_name_elapsed = ctx.dispatch_server_name_sw.Elapsed();
956 if (dispatch_server_name_elapsed != 0.0) {
957 extra.Print(prefix + "dispatch_server_name_time",
958 dispatch_server_name_elapsed);
959 }
960 }
961
962
963 ///////////////////////////////////////////////////////////////////////////////
CRuntimeData(const CDBConnectionFactory & parent,const CRef<IDBServiceMapper> & mapper)964 CDBConnectionFactory::CRuntimeData::CRuntimeData(
965 const CDBConnectionFactory& parent,
966 const CRef<IDBServiceMapper>& mapper
967 ) :
968 m_Parent(&parent),
969 m_DBServiceMapper(mapper)
970 {
971 }
972
973 IDBServiceMapper::TOptions&
GetServerOptions(const string & svc_name,bool force_refresh)974 CDBConnectionFactory::CRuntimeData::GetServerOptions(const string& svc_name,
975 bool force_refresh)
976 {
977 auto& options = m_ServerOptionsMap[svc_name];
978 if (force_refresh || options.empty()) {
979 m_DBServiceMapper->GetServerOptions(svc_name, &options);
980 // OK to leave empty if nothing turns up; service mappers can and
981 // do take responsibility for temporarily remembering negative
982 // results if checking from scratch is slow, and higher-level logic
983 // on this end falls back on GetServer as needed.
984 }
985 return options;
986 }
987
988 TSvrRef
GetDispatchedServer(const string & service_name)989 CDBConnectionFactory::CRuntimeData::GetDispatchedServer(
990 const string& service_name
991 )
992 {
993 return m_DispatchedSet[service_name];
994 }
995
996 void
SetDispatchedServer(const string & service_name,const TSvrRef & server)997 CDBConnectionFactory::CRuntimeData::SetDispatchedServer(
998 const string& service_name,
999 const TSvrRef& server
1000 )
1001 {
1002 if (server.Empty()) {
1003 m_DispatchNumMap[service_name] = 0;
1004 } else {
1005 ++m_DispatchNumMap[service_name];
1006 }
1007
1008 m_DispatchedSet[service_name] = server;
1009 }
1010
1011 unsigned int
GetNumOfDispatches(const string & service_name)1012 CDBConnectionFactory::CRuntimeData::GetNumOfDispatches(
1013 const string& service_name
1014 )
1015 {
1016 return m_DispatchNumMap[service_name];
1017 }
1018
1019 unsigned int
GetNumOfValidationFailures(const string & service_name)1020 CDBConnectionFactory::CRuntimeData::GetNumOfValidationFailures(
1021 const string& service_name
1022 )
1023 {
1024 return m_ValidationFailureMap[service_name];
1025 }
1026
1027 void
IncNumOfValidationFailures(const string & server_name,const TSvrRef & dsp_srv)1028 CDBConnectionFactory::CRuntimeData::IncNumOfValidationFailures(
1029 const string& server_name,
1030 const TSvrRef& dsp_srv
1031 )
1032 {
1033 ++m_ValidationFailureMap[server_name];
1034
1035 if (GetParent().GetMaxNumOfValidationAttempts() &&
1036 GetNumOfValidationFailures(server_name) >=
1037 GetParent().GetMaxNumOfValidationAttempts()) {
1038 // It is time to finish with this server ...
1039 Exclude(server_name, dsp_srv);
1040 }
1041 }
1042
GetExcluded(const string & service_name)1043 string CDBConnectionFactory::CRuntimeData::GetExcluded
1044 (const string& service_name)
1045 {
1046 IDBServiceMapper& mapper = GetDBServiceMapper();
1047 if ( !mapper.HasExclusions(service_name) ) {
1048 return kEmptyStr;
1049 }
1050
1051 IDBServiceMapper::TOptions options;
1052 mapper.GetServerOptions(service_name, &options);
1053 string result, delim;
1054 for (const auto& it : options) {
1055 if (it->IsExcluded()) {
1056 string exclusion;
1057 if (it->GetHost() != 0) {
1058 exclusion = impl::ConvertN2A(it->GetHost());
1059 if (it->GetPort() != 0) {
1060 exclusion += ':' + NStr::NumericToString(it->GetPort());
1061 }
1062 } else if ( !it->GetName().empty() ) {
1063 exclusion = it->GetName();
1064 }
1065 if ( !exclusion.empty() ) {
1066 result += delim + exclusion;
1067 delim = " ";
1068 }
1069 }
1070 }
1071 return result;
1072 }
1073
1074 ///////////////////////////////////////////////////////////////////////////////
CMapperFactory(IDBServiceMapper::TFactory svc_mapper_factory,const IRegistry * registry,EDefaultMapping def_mapping)1075 CDBConnectionFactory::CMapperFactory::CMapperFactory(
1076 IDBServiceMapper::TFactory svc_mapper_factory,
1077 const IRegistry* registry,
1078 EDefaultMapping def_mapping
1079 ) :
1080 m_SvcMapperFactory(svc_mapper_factory),
1081 m_Registry(registry),
1082 m_DefMapping(def_mapping)
1083 {
1084 CHECK_DRIVER_ERROR(!m_SvcMapperFactory && def_mapping != eUseDefaultMapper,
1085 "Database service name to server name mapper was not "
1086 "defined properly.",
1087 0);
1088 }
1089
1090
1091 IDBServiceMapper*
Make(void) const1092 CDBConnectionFactory::CMapperFactory::Make(void) const
1093 {
1094 if (m_DefMapping == eUseDefaultMapper) {
1095 CRef<CDBServiceMapperCoR> mapper(new CDBServiceMapperCoR());
1096
1097 mapper->Push(CRef<IDBServiceMapper>(new CDBDefaultServiceMapper()));
1098 if (m_SvcMapperFactory) {
1099 mapper->Push(CRef<IDBServiceMapper>(m_SvcMapperFactory(m_Registry)));
1100 }
1101
1102 return mapper.Release();
1103 } else {
1104 if (m_SvcMapperFactory) {
1105 return m_SvcMapperFactory(m_Registry);
1106 }
1107 }
1108
1109 return NULL;
1110 }
1111
1112
1113 ///////////////////////////////////////////////////////////////////////////////
CDBGiveUpFactory(IDBServiceMapper::TFactory svc_mapper_factory,const IRegistry * registry,EDefaultMapping def_mapping)1114 CDBGiveUpFactory::CDBGiveUpFactory(IDBServiceMapper::TFactory svc_mapper_factory,
1115 const IRegistry* registry,
1116 EDefaultMapping def_mapping)
1117 : CDBConnectionFactory(svc_mapper_factory, registry, def_mapping)
1118 {
1119 SetMaxNumOfConnAttempts(1); // This value is supposed to be default.
1120 SetMaxNumOfServerAlternatives(1); // Do not try other servers.
1121 }
1122
~CDBGiveUpFactory(void)1123 CDBGiveUpFactory::~CDBGiveUpFactory(void)
1124 {
1125 }
1126
1127 ///////////////////////////////////////////////////////////////////////////////
CDBRedispatchFactory(IDBServiceMapper::TFactory svc_mapper_factory,const IRegistry * registry,EDefaultMapping def_mapping)1128 CDBRedispatchFactory::CDBRedispatchFactory(IDBServiceMapper::TFactory svc_mapper_factory,
1129 const IRegistry* registry,
1130 EDefaultMapping def_mapping)
1131 : CDBConnectionFactory(svc_mapper_factory, registry, def_mapping)
1132 {
1133 SetMaxNumOfDispatches(1);
1134 SetMaxNumOfValidationAttempts(0); // Unlimited ...
1135 }
1136
~CDBRedispatchFactory(void)1137 CDBRedispatchFactory::~CDBRedispatchFactory(void)
1138 {
1139 }
1140
1141
1142 ///////////////////////////////////////////////////////////////////////////////
CConnValidatorCoR(void)1143 CConnValidatorCoR::CConnValidatorCoR(void)
1144 {
1145 }
1146
~CConnValidatorCoR(void)1147 CConnValidatorCoR::~CConnValidatorCoR(void)
1148 {
1149 }
1150
1151 IConnValidator::EConnStatus
Validate(CDB_Connection & conn)1152 CConnValidatorCoR::Validate(CDB_Connection& conn)
1153 {
1154 CFastMutexGuard mg(m_Mtx);
1155
1156 NON_CONST_ITERATE(TValidators, vr_it, m_Validators) {
1157 EConnStatus status = (*vr_it)->Validate(conn);
1158
1159 // Exit if we met an invalid connection ...
1160 if (status != eValidConn) {
1161 return status;
1162 }
1163 }
1164 return eValidConn;
1165 }
1166
1167 string
GetName(void) const1168 CConnValidatorCoR::GetName(void) const
1169 {
1170 string result("CConnValidatorCoR");
1171
1172 CFastMutexGuard mg(m_Mtx);
1173
1174 ITERATE(TValidators, vr_it, m_Validators) {
1175 result += (*vr_it)->GetName();
1176 }
1177
1178 return result;
1179 }
1180
1181 void
Push(const CRef<IConnValidator> & validator)1182 CConnValidatorCoR::Push(const CRef<IConnValidator>& validator)
1183 {
1184 if (validator.NotNull()) {
1185 CFastMutexGuard mg(m_Mtx);
1186
1187 m_Validators.push_back(validator);
1188 }
1189 }
1190
1191 void
Pop(void)1192 CConnValidatorCoR::Pop(void)
1193 {
1194 CFastMutexGuard mg(m_Mtx);
1195
1196 m_Validators.pop_back();
1197 }
1198
1199 CRef<IConnValidator>
Top(void) const1200 CConnValidatorCoR::Top(void) const
1201 {
1202 CFastMutexGuard mg(m_Mtx);
1203
1204 return m_Validators.back();
1205 }
1206
1207 bool
Empty(void) const1208 CConnValidatorCoR::Empty(void) const
1209 {
1210 CFastMutexGuard mg(m_Mtx);
1211
1212 return m_Validators.empty();
1213 }
1214
1215 ///////////////////////////////////////////////////////////////////////////////
CTrivialConnValidator(const string & db_name,int attr)1216 CTrivialConnValidator::CTrivialConnValidator(const string& db_name,
1217 int attr) :
1218 m_DBName(db_name),
1219 m_Attr(attr)
1220 {
1221 }
1222
~CTrivialConnValidator(void)1223 CTrivialConnValidator::~CTrivialConnValidator(void)
1224 {
1225 }
1226
1227 /* Future development ...
1228 IConnValidator::EConnStatus
1229 CTrivialConnValidator::Validate(CDB_Connection& conn)
1230 {
1231 string curr_dbname;
1232
1233 // Get current database name ...
1234 {
1235 unique_ptr<CDB_LangCmd> auto_stmt(conn.LangCmd("select db_name()"));
1236 auto_stmt->Send();
1237 while (auto_stmt->HasMoreResults()) {
1238 unique_ptr<CDB_Result> rs(auto_stmt->Result());
1239
1240 if (rs.get() == NULL) {
1241 continue;
1242 }
1243
1244 if (rs->ResultType() != eDB_RowResult) {
1245 continue;
1246 }
1247
1248 while (rs->Fetch()) {
1249 CDB_VarChar db_name;
1250 rs->GetItem(&db_name);
1251 curr_dbname = static_cast<const string&>(db_name);
1252 }
1253 }
1254 }
1255 // Try to change a database ...
1256 if (curr_dbname != GetDBName()) {
1257 conn.SetDatabaseName(GetDBName());
1258 }
1259
1260 if (GetAttr() & eCheckSysobjects) {
1261 unique_ptr<CDB_LangCmd> set_cmd(conn.LangCmd("SELECT id FROM sysobjects"));
1262 set_cmd->Send();
1263 set_cmd->DumpResults();
1264 }
1265
1266 // Go back to the original (master) database ...
1267 if (GetAttr() & eRestoreDefaultDB && curr_dbname != GetDBName()) {
1268 conn.SetDatabaseName(curr_dbname);
1269 }
1270
1271 // All exceptions are supposed to be caught and processed by
1272 // CDBConnectionFactory ...
1273 return eValidConn;
1274 }
1275 */
1276
1277 IConnValidator::EConnStatus
Validate(CDB_Connection & conn)1278 CTrivialConnValidator::Validate(CDB_Connection& conn)
1279 {
1280 // Try to change a database ...
1281 conn.SetDatabaseName(GetDBName());
1282
1283 if (GetAttr() & eCheckSysobjects) {
1284 unique_ptr<CDB_LangCmd> set_cmd(conn.LangCmd("SELECT id FROM sysobjects"));
1285 set_cmd->Send();
1286 set_cmd->DumpResults();
1287 }
1288
1289 // Go back to the original (master) database ...
1290 if (GetAttr() & eRestoreDefaultDB) {
1291 conn.SetDatabaseName("master");
1292 }
1293
1294 // All exceptions are supposed to be caught and processed by
1295 // CDBConnectionFactory ...
1296 return eValidConn;
1297 }
1298
1299 string
GetName(void) const1300 CTrivialConnValidator::GetName(void) const
1301 {
1302 string result("CTrivialConnValidator");
1303
1304 result += (GetAttr() == eCheckSysobjects ? "CSO" : "");
1305 result += GetDBName();
1306
1307 return result;
1308 }
1309
1310 END_NCBI_SCOPE
1311