CDB_Connection* CDBConnectionFactory::MakeDBConnection( I_DriverContext& ctx, const CDBConnParams& params) { CFastMutexGuard mg(m_Mtx); CDB_UserHandler::ClearExceptions(m_Errors); CDB_Connection* t_con = NULL; CRuntimeData& rt_data = GetRuntimeData(params.GetConnValidator()); TSvrRef dsp_srv = rt_data.GetDispatchedServer(params.GetServerName()); // Prepare to collect messages, whose proper severity depends on whether // ANY attempt succeeds. impl::CDBHandlerStack ultimate_handlers; {{ const impl::CDriverContext* ctx_impl = dynamic_cast<impl::CDriverContext*>(&ctx); if (params.GetOpeningMsgHandlers().GetSize() > 0) { ultimate_handlers = params.GetOpeningMsgHandlers(); } else if (ctx_impl != NULL) { ultimate_handlers = ctx_impl->GetCtxHandlerStack(); } else { ultimate_handlers.Push(&CDB_UserHandler::GetDefault()); } }} SOpeningContext opening_ctx(ctx); CRef<CDB_UserHandler_Deferred> handler (new CDB_UserHandler_Deferred(ultimate_handlers)); opening_ctx.handlers.Push(&*handler, eTakeOwnership); // Store original query timeout ... unsigned int query_timeout = ctx.GetTimeout(); // Set "validation timeouts" ... ctx.SetTimeout(CalculateConnectionTimeout(ctx)); ctx.SetLoginTimeout(CalculateLoginTimeout(ctx)); if ( dsp_srv.Empty() ) { // We are here either because server name was never dispatched or // because a named connection pool has been used before. // Dispatch server name ... t_con = DispatchServerName(opening_ctx, params); } else { // Server name is already dispatched ... string single_server(params.GetParam("single_server")); // We probably need to re-dispatch it ... if (single_server != "true" && GetMaxNumOfDispatches() && rt_data.GetNumOfDispatches(params.GetServerName()) >= GetMaxNumOfDispatches()) { // We definitely need to re-dispatch it ... // Clean previous info ... rt_data.SetDispatchedServer(params.GetServerName(), TSvrRef()); t_con = DispatchServerName(opening_ctx, params); } else { // We do not need to re-dispatch it ... // Try to connect. try { // I_DriverContext::SConnAttr cur_conn_attr(conn_attr); // cur_conn_attr.srv_name = dsp_srv->GetName(); CDB_DBLB_Delegate cur_params( dsp_srv->GetName(), dsp_srv->GetHost(), dsp_srv->GetPort(), params); cur_params.SetOpeningMsgHandlers() = opening_ctx.handlers; // MakeValidConnection may return NULL here because a newly // created connection may not pass validation. t_con = MakeValidConnection(opening_ctx, // cur_conn_attr, cur_params); } catch (CDB_Exception& ex) { // m_Errors.push_back(ex.Clone()); opening_ctx.handlers.PostMsg(&ex); if (params.GetConnValidator()) { opening_ctx.conn_status = params.GetConnValidator()->ValidateException(ex); } } if (!t_con) { // We couldn't connect ... if (single_server != "true") { // Server might be temporarily unavailable ... // Check conn_status ... if (opening_ctx.conn_status == IConnValidator::eTempInvalidConn) { rt_data.IncNumOfValidationFailures(params.GetServerName(), dsp_srv); } // Re-dispatch ... t_con = DispatchServerName(opening_ctx, params); } } else { // Dispatched server is already set, but calling of this method // will increase number of successful dispatches. rt_data.SetDispatchedServer(params.GetServerName(), dsp_srv); } } } // Restore original connection timeout ... ctx.SetTimeout(query_timeout); // Restore original query timeout ... if (t_con) { t_con->SetTimeout(query_timeout); } x_LogConnection(opening_ctx, t_con, params); handler->Flush((t_con == NULL) ? eDiagSevMax : eDiag_Warning); return t_con; }