1 /* $Id: exception.cpp 606565 2020-04-23 15:24:30Z ucko $
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  * Author:  Denis Vakatov, Vladimir Soussov
27  *
28  * File Description:  Exceptions
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 #include <dbapi/driver/exception.hpp>
34 #include <dbapi/driver/interfaces.hpp>
35 #include <dbapi/driver/impl/dbapi_impl_connection.hpp>
36 #include <dbapi/error_codes.hpp>
37 #include <corelib/ncbi_safe_static.hpp>
38 
39 
40 #define NCBI_USE_ERRCODE_X   Dbapi_DrvrExcepts
41 
42 
43 BEGIN_NCBI_SCOPE
44 
45 
46 /////////////////////////////////////////////////////////////////////////////
47 //  CDB_Exception::
48 //
49 
~SParams(void)50 CDB_Exception::SParams::~SParams(void)
51 {
52     ITERATE (TParams, it, params) {
53         if (it->value != NULL) {
54             delete it->value;
55         }
56     }
57 }
58 
SContext(const CDBConnParams & params)59 CDB_Exception::SContext::SContext(const CDBConnParams& params)
60     : server_name(params.GetServerName()),
61       username(params.GetUserName())
62       // database_name(params.GetDatabaseName())
63 {
64 }
65 
UpdateFrom(const SContext & ctx)66 void CDB_Exception::SContext::UpdateFrom(const SContext& ctx)
67 {
68     // favor new context
69     if ( !ctx.server_name.empty()   ) { server_name   = ctx.server_name;   }
70     if ( !ctx.username.empty()      ) { username      = ctx.username;      }
71     if ( !ctx.database_name.empty() ) { database_name = ctx.database_name; }
72     if ( !ctx.extra_msg.empty()     ) { extra_msg     = ctx.extra_msg;     }
73 }
74 
operator <<(ostream & os,const CDB_Exception::SContext & ctx)75 ostream& operator<<(ostream &os, const CDB_Exception::SContext& ctx)
76 {
77     const char* delim = kEmptyCStr;
78     if ( !ctx.server_name.empty() ) {
79         os << delim << "SERVER: '" << ctx.server_name << '\'';
80         delim = " ";
81     }
82     if ( !ctx.username.empty() ) {
83         os << delim << "USER: '" << ctx.username << '\'';
84         delim = " ";
85     }
86     if ( !ctx.database_name.empty() ) {
87         os << delim << "DATABASE: '" << ctx.database_name << '\'';
88         delim = " ";
89     }
90     if ( !ctx.extra_msg.empty() ) {
91         os << delim << ctx.extra_msg;
92     }
93     return os;
94 }
95 
operator +(const SContext & new_context) const96 CDB_Exception::SMessageInContext CDB_Exception::SMessageInContext::operator+
97 (const SContext& new_context) const
98 {
99     if (context.Empty()) {
100         return SMessageInContext(message, new_context);
101     } else {
102         CRef<SContext> merged_context(new SContext(*context));
103         merged_context->UpdateFrom(new_context);
104         return SMessageInContext(message, *merged_context);
105     }
106 }
107 
operator <<(ostream & os,const CDB_Exception::SMessageInContext & msg)108 ostream& operator<<(ostream &os, const CDB_Exception::SMessageInContext& msg)
109 {
110     os << msg.message;
111     if (msg.context.NotEmpty()) {
112         os << ' ' << *msg.context;
113     }
114     return os;
115 }
116 
117 EDB_Severity
Severity(void) const118 CDB_Exception::Severity(void) const
119 {
120     EDB_Severity result = eDB_Unknown;
121 
122     switch ( GetSeverity() ) {
123     case eDiag_Info:
124         result = eDB_Info;
125         break;
126     case eDiag_Warning:
127         result = eDB_Warning;
128         break;
129     case eDiag_Error:
130         result = eDB_Error;
131         break;
132     case eDiag_Critical:
133         result = eDB_Fatal;
134         break;
135     case eDiag_Fatal:
136         result = eDB_Fatal;
137         break;
138     case eDiag_Trace:
139         result = eDB_Fatal;
140         break;
141     }
142 
143     return result;
144 }
145 
146 const char*
SeverityString(void) const147 CDB_Exception::SeverityString(void) const
148 {
149     return CNcbiDiag::SeverityName( GetSeverity() );
150 }
151 
SeverityString(EDB_Severity sev)152 const char* CDB_Exception::SeverityString(EDB_Severity sev)
153 {
154     EDiagSev dsev = eDiag_Info;
155 
156     switch ( sev ) {
157     case eDB_Info:
158         dsev = eDiag_Info;
159         break;
160     case eDB_Warning:
161         dsev = eDiag_Warning;
162         break;
163     case eDB_Error:
164         dsev = eDiag_Error;
165         break;
166     case eDB_Fatal:
167         dsev = eDiag_Fatal;
168         break;
169     case eDB_Unknown:
170         dsev = eDiag_Info;
171         break;
172     }
173     return CNcbiDiag::SeverityName( dsev );
174 }
175 
176 
SetFromConnection(const impl::CConnection & connection)177 void CDB_Exception::SetFromConnection(const impl::CConnection& connection)
178 {
179     if (GetServerName().empty()  &&  !connection.ServerName().empty()) {
180         SetServerName(connection.ServerName());
181         // AddToMessage(" SERVER: '" + connection.ServerName() + '\'');
182     }
183     if (GetUserName().empty()  &&  !connection.UserName().empty()) {
184         SetUserName(connection.UserName());
185         // AddToMessage(" USER: '" + connection.UserName() + '\'');
186     }
187     if (GetDatabaseName().empty()  &&  !connection.GetDatabaseName().empty()) {
188         SetDatabaseName(connection.GetDatabaseName());
189         // AddToMessage(" DATABASE: '" + connection.GetDatabaseName() + '\'');
190     }
191 }
192 
193 
194 void
SetParams(const CDBParams * params)195 CDB_Exception::SetParams(const CDBParams* params)
196 {
197     unsigned int n = params ? params->GetNum() : 0;
198     if (n == 0) {
199         return;
200     }
201     if (m_Params.Empty()) {
202         m_Params.Reset(new SParams);
203     }
204 
205     SParams::TParams& my_params = m_Params->params;
206     my_params.resize(n);
207     for (unsigned int i = 0;  i < n;  ++i) {
208         my_params[i].value = NULL;
209     }
210     for (unsigned int i = 0;  i < n;  ++i) {
211         SParam& p = my_params[i];
212         p.name = params->GetName(i);
213         try {
214             const CDB_Object* v = params->GetValue(i);
215             if (v != NULL) {
216                 p.value = v->ShallowClone();
217             }
218         } catch (exception&) {
219         }
220     }
221 }
222 
223 
224 void
ReportExtra(ostream & out) const225 CDB_Exception::ReportExtra(ostream& out) const
226 {
227     x_StartOfWhat( out );
228     x_EndOfWhat( out );
229 }
230 
231 void
x_StartOfWhat(ostream & out) const232 CDB_Exception::x_StartOfWhat(ostream& out) const
233 {
234     out << *m_Context;
235     out << " [";
236     out << SeverityString();
237     out << " #";
238     out << NStr::IntToString( GetDBErrCode() );
239     out << ", ";
240     out << GetType();
241     out << "]";
242 }
243 
244 
245 void
x_EndOfWhat(ostream & out) const246 CDB_Exception::x_EndOfWhat(ostream& out) const
247 {
248 //     out << "<<<";
249 //     out << GetMsg();
250 //     out << ">>>";
251     if ( !m_Params.Empty()  &&  !m_Params->params.empty() ) {
252         if (m_RowsInBatch <= 1) {
253             out << " [Parameters: ";
254         } else {
255             out << " [Error occurred somewhere in the " << m_RowsInBatch
256                 << "-row BCP batch whose final row was ";
257         }
258         const char* delim = kEmptyCStr;
259         ITERATE (SParams::TParams, it, m_Params->params) {
260             out << delim;
261             if ( !it->name.empty() ) {
262                 out << it->name << " = ";
263             }
264             if (it->value) {
265                 out << it->value->GetLogString();
266             } else {
267                 out << "(null)";
268             }
269             delim = ", ";
270         }
271         out << ']';
272     }
273 }
274 
275 static CSafeStatic<CDB_Exception::SContext> kEmptyContext;
276 
x_Init(const CDiagCompileInfo & info,const string & message,const CException * prev_exception,EDiagSev severity)277 void CDB_Exception::x_Init(const CDiagCompileInfo& info, const string& message,
278                            const CException* prev_exception, EDiagSev severity)
279 {
280     CException::x_Init(info, message, prev_exception, severity);
281     if (m_Context.Empty()) {
282         m_Context.Reset(&kEmptyContext.Get());
283     }
284 }
285 
286 void
x_Assign(const CException & src)287 CDB_Exception::x_Assign(const CException& src)
288 {
289     const CDB_Exception& other = dynamic_cast<const CDB_Exception&>(src);
290 
291     CException::x_Assign(src);
292 
293     m_DBErrCode = other.m_DBErrCode;
294     m_Context   = other.m_Context;
295     m_SybaseSeverity = other.m_SybaseSeverity;
296     m_Params = other.m_Params;
297     m_RowsInBatch = other.m_RowsInBatch;
298 }
299 
x_SetContext(void)300 CDB_Exception::SContext& CDB_Exception::x_SetContext(void)
301 {
302     // Unshare if necessary
303     if ( !m_Context->ReferencedOnlyOnce() ) {
304         m_Context.Reset(new SContext(*m_Context));
305     }
306     return const_cast<SContext&>(*m_Context);
307 }
308 
309 const char*
GetErrCodeString(void) const310 CDB_Exception::GetErrCodeString(void) const
311 {
312     switch ( x_GetErrCode() ) {
313         case eDS:       return "eDS";
314         case eRPC:      return "eRPC";
315         case eSQL:      return "eSQL";
316         case eDeadlock: return "eDeadlock";
317         case eTimeout:  return "eTimeout";
318         case eClient:   return "eClient";
319         case eMulti:    return "eMulti";
320         case eTruncate: return "eTruncate";
321         default:        return CException::GetErrCodeString();
322     }
323 }
324 
325 CDB_Exception*
Clone(void) const326 CDB_Exception::Clone(void) const
327 {
328     return new CDB_Exception(*this);
329 }
330 
331 CDB_Exception::EType
Type(void) const332 CDB_Exception::Type(void) const
333 {
334     int err_code = x_GetErrCode();
335 
336     if (err_code > eMulti) {
337         err_code = eInvalid;
338     }
339 
340     return static_cast<EType>(err_code);
341 }
342 
343 /////////////////////////////////////////////////////////////////////////////
344 //  CDB_RPCEx::
345 //
346 
347 void
ReportExtra(ostream & out) const348 CDB_RPCEx::ReportExtra(ostream& out) const
349 {
350     string extra_value;
351 
352     x_StartOfWhat( out );
353 
354     out << " Procedure '";
355     out << ProcName();
356     out << "', Line ";
357     out << NStr::IntToString( ProcLine() );
358 
359     x_EndOfWhat( out );
360 }
361 
362 
363 void
x_Assign(const CException & src)364 CDB_RPCEx::x_Assign(const CException& src)
365 {
366     const CDB_RPCEx& other = dynamic_cast<const CDB_RPCEx&>(src);
367 
368     CDB_Exception::x_Assign(src);
369     m_ProcName = other.m_ProcName;
370     m_ProcLine = other.m_ProcLine;
371 }
372 
373 
374 
375 /////////////////////////////////////////////////////////////////////////////
376 //  CDB_SQLEx::
377 //
378 
379 void
ReportExtra(ostream & out) const380 CDB_SQLEx::ReportExtra(ostream& out) const
381 {
382     x_StartOfWhat( out );
383 
384     out << " Procedure '";
385     out << SqlState();
386     out << "', Line ";
387     out << NStr::IntToString(BatchLine());
388 
389     x_EndOfWhat( out );
390 }
391 
392 void
x_Assign(const CException & src)393 CDB_SQLEx::x_Assign(const CException& src)
394 {
395     const CDB_SQLEx& other = dynamic_cast<const CDB_SQLEx&>(src);
396 
397     CDB_Exception::x_Assign(src);
398     m_SqlState = other.m_SqlState;
399     m_BatchLine = other.m_BatchLine;
400 }
401 
402 
403 /////////////////////////////////////////////////////////////////////////////
404 //  CDB_MultiEx::
405 //
406 
407 void
x_Assign(const CException & src)408 CDB_MultiEx::x_Assign(const CException& src)
409 {
410     const CDB_MultiEx& other = dynamic_cast<const CDB_MultiEx&>(src);
411 
412     CDB_Exception::x_Assign(src);
413     m_Bag = other.m_Bag;
414     m_NofRooms = other.m_NofRooms;
415 }
416 
417 bool
Push(const CDB_Exception & ex)418 CDB_MultiEx::Push(const CDB_Exception& ex)
419 {
420     if ( ex.GetErrCode() == eMulti ) {
421         CDB_MultiEx& mex =
422             const_cast<CDB_MultiEx&> ( dynamic_cast<const CDB_MultiEx&> (ex) );
423 
424         CDB_Exception* pex = NULL;
425         while ( (pex = mex.Pop()) != NULL ) {
426             m_Bag->GetData().push_back( pex );
427         }
428     } else {
429         // this is an ordinary exception
430         // Clone it ...
431         const CException* tmp_ex = ex.x_Clone();
432         const CDB_Exception* except_copy = dynamic_cast<const CDB_Exception*>(tmp_ex);
433 
434         // Store it ...
435         if ( except_copy ) {
436             m_Bag->GetData().push_back( except_copy );
437         } else {
438             delete tmp_ex;
439             return false;
440         }
441     }
442     return true;
443 }
444 
445 CDB_Exception*
Pop(void)446 CDB_MultiEx::Pop(void)
447 {
448     if ( m_Bag->GetData().empty() ) {
449         return NULL;
450     }
451 
452     const CDB_Exception* result = m_Bag->GetData().back().release();
453     m_Bag->GetData().pop_back();
454 
455     // Remove "const" from the object because we do not own it any more ...
456     return const_cast<CDB_Exception*>(result);
457 }
458 
WhatThis(void) const459 string CDB_MultiEx::WhatThis(void) const
460 {
461     string str;
462 
463     str += "---  [Multi-Exception";
464     if (!GetModule().empty()) {
465         str += " in ";
466         str += GetModule();
467     }
468     str += "]   Contains a backtrace of ";
469     str += NStr::UIntToString( NofExceptions() );
470     str += " exception";
471     str += NofExceptions() == 1 ? "" : "s";
472     str += "  ---";
473 
474     return str;
475 }
476 
477 
478 void
ReportExtra(ostream & out) const479 CDB_MultiEx::ReportExtra(ostream& out) const
480 {
481     out
482         << WhatThis()
483         << Endl();
484 
485     ReportErrorStack(out);
486 
487     out
488         << Endl()
489         << "---  [Multi-Exception]  End of backtrace  ---";
490 }
491 
492 void
ReportErrorStack(ostream & out) const493 CDB_MultiEx::ReportErrorStack(ostream& out) const
494 {
495     size_t record_num = m_Bag->GetData().size();
496 
497     if ( record_num == 0 ) {
498         return;
499     }
500 
501     if ( record_num > m_NofRooms ) {
502         out << " *** Too many exceptions -- the last ";
503         out << NStr::UInt8ToString( record_num - m_NofRooms );
504         out << " exceptions are not shown ***";
505     }
506 
507     TExceptionStack::const_reverse_iterator criter = m_Bag->GetData().rbegin();
508     TExceptionStack::const_reverse_iterator eriter = m_Bag->GetData().rend();
509 
510     for ( unsigned int i = 0; criter != eriter && i < m_NofRooms; ++criter, ++i ) {
511         out << Endl();
512         out << "  ";
513         out << (*criter)->what();
514     }
515 }
516 
517 /////////////////////////////////////////////////////////////////////////////
518 //  CDB_UserHandler_Wrapper::  wrapper for the actual current handler
519 //
520 //    NOTE:  it is a singleton
521 //
522 
523 
524 class CDB_UserHandler_Wrapper : public CDB_UserHandler
525 {
526 public:
527     CDB_UserHandler_Wrapper(void);
528 
529     CDB_UserHandler* Set(CDB_UserHandler* h);
530 
531     virtual bool HandleAll(const TExceptions& exceptions);
532     virtual bool HandleIt(CDB_Exception* ex);
533     virtual bool HandleMessage(int severity, int msgnum,
534                                const string& message);
535 
536     virtual ~CDB_UserHandler_Wrapper();
537 
538 private:
539     CRef<CDB_UserHandler> m_Handler;
540 };
541 
542 
CDB_UserHandler_Wrapper(void)543 CDB_UserHandler_Wrapper::CDB_UserHandler_Wrapper(void) :
544 m_Handler(new CDB_UserHandler_Default)
545 {
546 }
547 
Set(CDB_UserHandler * h)548 CDB_UserHandler* CDB_UserHandler_Wrapper::Set(CDB_UserHandler* h)
549 {
550     if (h == this) {
551         throw runtime_error("CDB_UserHandler_Wrapper::Reset() -- attempt "
552                             "to set handle wrapper as a handler");
553     }
554 
555     if (h == m_Handler) {
556         return NULL;
557     }
558 
559     CDB_UserHandler* prev_h = m_Handler.Release();
560     m_Handler = h;
561     return prev_h;
562 }
563 
564 
~CDB_UserHandler_Wrapper()565 CDB_UserHandler_Wrapper::~CDB_UserHandler_Wrapper()
566 {
567 }
568 
569 
HandleIt(CDB_Exception * ex)570 bool CDB_UserHandler_Wrapper::HandleIt(CDB_Exception* ex)
571 {
572     return m_Handler ? m_Handler->HandleIt(ex) : false;
573 }
574 
575 
HandleAll(const TExceptions & exceptions)576 bool CDB_UserHandler_Wrapper::HandleAll(const TExceptions& exceptions)
577 {
578     return m_Handler ? m_Handler->HandleAll(exceptions) : false;
579 }
580 
581 
HandleMessage(int severity,int msgnum,const string & message)582 bool CDB_UserHandler_Wrapper::HandleMessage(int severity, int msgnum,
583                                             const string& message)
584 {
585     return m_Handler ? m_Handler->HandleMessage(severity, msgnum, message)
586         : false;
587 }
588 
589 
590 /////////////////////////////////////////////////////////////////////////////
591 //  CDB_UserHandler::
592 //
593 
CDB_UserHandler(void)594 CDB_UserHandler::CDB_UserHandler(void)
595 {
596 }
597 
~CDB_UserHandler(void)598 CDB_UserHandler::~CDB_UserHandler(void)
599 {
600 }
601 
602 void
ClearExceptions(TExceptions & expts)603 CDB_UserHandler::ClearExceptions(TExceptions& expts)
604 {
605     NON_CONST_ITERATE(CDB_UserHandler::TExceptions, it, expts) {
606         CDB_Exception* ex = *it; // for debugging ...
607         delete ex;
608     }
609     expts.clear();
610 }
611 
612 
613 //
614 // ATTENTION:  Should you change the following static methods, please make sure
615 //             to rebuild all DLLs which have this code statically linked in!
616 //
617 
GetDefaultCDBErrorHandler(void)618 static CDB_UserHandler_Wrapper& GetDefaultCDBErrorHandler(void)
619 {
620     static CSafeStatic<CDB_UserHandler_Wrapper> s_CDB_DefUserHandler;
621 
622     return s_CDB_DefUserHandler.Get();
623 }
624 
GetDefault(void)625 CDB_UserHandler& CDB_UserHandler::GetDefault(void)
626 {
627     return GetDefaultCDBErrorHandler();
628 }
629 
630 
SetDefault(CDB_UserHandler * h)631 CDB_UserHandler* CDB_UserHandler::SetDefault(CDB_UserHandler* h)
632 {
633     return GetDefaultCDBErrorHandler().Set(h);
634 }
635 
636 
HandleAll(const TExceptions &)637 bool CDB_UserHandler::HandleAll(const TExceptions& /* exceptions */)
638 {
639     // return x_HandleAll(exceptions);
640     return false;
641 }
642 
x_HandleAll(const TExceptions &)643 bool CDB_UserHandler::x_HandleAll(const TExceptions& /* exceptions */)
644 {
645 #if 1
646     return false;
647 #else
648     // Better done in CDBHandlerStack::HandleExceptions, which can
649     // keep track of which exceptions still need handling.
650     bool handled_all = true;
651     ITERATE (TExceptions, it, exceptions) {
652         handled_all &= HandleIt(*it);
653     }
654     return handled_all;
655 #endif
656 }
657 
HandleMessage(int,int,const string &)658 bool CDB_UserHandler::HandleMessage(int /* severity */,
659                                     int /* msgnum */,
660                                     const string& /* message */)
661 {
662     return false;
663 }
664 
665 
GetExtraMsg(void) const666 string CDB_UserHandler::GetExtraMsg(void) const
667 {
668     return "Method CDB_UserHandler::GetExtraMsg is deprecated. "
669            "Use CDB_Exception::GetExtraMsg instead.";
670 }
671 
SetExtraMsg(const string &) const672 void CDB_UserHandler::SetExtraMsg(const string&) const
673 {
674 }
675 
676 
677 /////////////////////////////////////////////////////////////////////////////
678 //  CDB_UserHandler_Diag::
679 //
680 
681 
CDB_UserHandler_Diag(const string & prefix)682 CDB_UserHandler_Diag::CDB_UserHandler_Diag(const string& prefix)
683     : m_Prefix(prefix)
684 {
685     return;
686 }
687 
688 
~CDB_UserHandler_Diag()689 CDB_UserHandler_Diag::~CDB_UserHandler_Diag()
690 {
691     try {
692         m_Prefix.erase();
693     }
694     NCBI_CATCH_ALL_X( 5, NCBI_CURRENT_FUNCTION )
695 }
696 
697 
HandleIt(CDB_Exception * ex)698 bool CDB_UserHandler_Diag::HandleIt(CDB_Exception* ex)
699 {
700     if ( !ex )
701         return true;
702 
703     if (ex->GetSeverity() == eDiag_Info) {
704         if ( m_Prefix.empty() ) {
705             ERR_POST_X(1, Info << ex->GetMsg());
706         } else {
707             ERR_POST_X(2, Info << m_Prefix << " " << ex->GetMsg());
708         }
709     }
710     else {
711         if ( m_Prefix.empty() ) {
712             ERR_POST_X(3, *ex);
713         } else {
714             ERR_POST_X(4, Severity(ex->GetSeverity()) << m_Prefix << " " << *ex);
715         }
716     }
717 
718     return true;
719 }
720 
721 
HandleAll(const TExceptions & exceptions)722 bool CDB_UserHandler_Diag::HandleAll(const TExceptions& exceptions)
723 {
724     return x_HandleAll(exceptions);
725 }
726 
727 
728 
729 /////////////////////////////////////////////////////////////////////////////
730 //  CDB_UserHandler_Stream::
731 //
732 
733 
CDB_UserHandler_Stream(ostream * os,const string & prefix,bool own_os)734 CDB_UserHandler_Stream::CDB_UserHandler_Stream(ostream*      os,
735                                                const string& prefix,
736                                                bool          own_os)
737     : m_Output(os ? os : &cerr),
738       m_Prefix(prefix),
739       m_OwnOutput(own_os)
740 {
741     if (m_OwnOutput && (m_Output == &cerr || m_Output == &cout)) {
742         m_OwnOutput = false;
743     }
744 }
745 
746 
~CDB_UserHandler_Stream()747 CDB_UserHandler_Stream::~CDB_UserHandler_Stream()
748 {
749     try {
750         if ( m_OwnOutput ) {
751             delete m_Output;
752             m_OwnOutput = false;
753             m_Output = 0;
754         }
755 
756         m_Prefix.erase();
757     }
758     NCBI_CATCH_ALL_X( 6, NCBI_CURRENT_FUNCTION )
759 }
760 
761 
HandleIt(CDB_Exception * ex)762 bool CDB_UserHandler_Stream::HandleIt(CDB_Exception* ex)
763 {
764     if ( !ex )
765         return true;
766 
767     if ( !m_Output )
768         return false;
769 
770     CFastMutexGuard mg(m_Mtx);
771 
772     if ( !m_Prefix.empty() ) {
773         *m_Output << m_Prefix << " ";
774     }
775 
776     *m_Output << ex->what();
777     *m_Output << endl;
778 
779     return m_Output->good();
780 }
781 
782 
HandleAll(const TExceptions & exceptions)783 bool CDB_UserHandler_Stream::HandleAll(const TExceptions& exceptions)
784 {
785     return x_HandleAll(exceptions);
786 }
787 
788 
789 ////////////////////////////////////////////////////////////////////////////////
790 //  CDB_UserHandler_Exception::
791 //
792 
~CDB_UserHandler_Exception(void)793 CDB_UserHandler_Exception::~CDB_UserHandler_Exception(void)
794 {
795 }
796 
797 bool
HandleIt(CDB_Exception * ex)798 CDB_UserHandler_Exception::HandleIt(CDB_Exception* ex)
799 {
800     if (!ex  ||  ex->GetSeverity() == eDiag_Info)
801         return false;
802 
803     // Ignore errors with ErrorCode set to 0
804     // (this is related mostly to the FreeTDS driver)
805     if (ex->GetDBErrCode() == 0)
806         return true;
807 
808     CDB_TruncateEx* trunc_ex = dynamic_cast<CDB_TruncateEx*>(ex);
809 
810     if (trunc_ex) {
811         ERR_POST_X(7, *ex);
812         return true;
813     }
814 
815     ex->Throw();
816 
817     return true;
818 }
819 
820 bool
HandleAll(const TExceptions & exceptions)821 CDB_UserHandler_Exception::HandleAll(const TExceptions& exceptions)
822 {
823     if (exceptions.empty())
824         return false;
825 
826     TExceptions::const_iterator it = exceptions.end();
827     CDB_Exception* outer_ex = NULL;
828     bool ret_val = false;
829     while (it != exceptions.begin()  &&  !outer_ex) {
830         --it;
831         outer_ex = *it;
832         if (outer_ex) {
833             if (outer_ex->GetSeverity() == eDiag_Info)
834                 outer_ex = NULL;
835             else if (outer_ex->GetDBErrCode() == 0) {
836                 outer_ex = NULL;
837                 ret_val = true;
838             }
839             else {
840                 CDB_TruncateEx* trunc_ex = dynamic_cast<CDB_TruncateEx*>(outer_ex);
841                 if (trunc_ex) {
842                     ERR_POST_X(7, *trunc_ex);
843                     outer_ex = NULL;
844                     ret_val = true;
845                 }
846             }
847         }
848     }
849     if (!outer_ex)
850         return ret_val;
851 
852     if (it != exceptions.begin()) {
853         do {
854             --it;
855             if (*it)
856                 outer_ex->AddPrevious(*it);
857         }
858         while (it != exceptions.begin());
859     }
860 
861     outer_ex->Throw();
862     return true;
863 }
864 
865 
866 ////////////////////////////////////////////////////////////////////////////////
867 //  CDB_UserHandler_Deferred::
868 //
869 
CDB_UserHandler_Deferred(const impl::CDBHandlerStack & ultimate_handlers)870 CDB_UserHandler_Deferred::CDB_UserHandler_Deferred
871 (const impl::CDBHandlerStack& ultimate_handlers)
872     : m_UltimateHandlers(ultimate_handlers)
873 {
874 }
875 
~CDB_UserHandler_Deferred(void)876 CDB_UserHandler_Deferred::~CDB_UserHandler_Deferred(void)
877 {
878     if ( !m_SavedExceptions.empty() ) {
879         ERR_POST_X(8, Warning << "Internal bug: Found unreported exceptions."
880                    << CStackTrace());
881         bool done = false;
882         while ( !done ) {
883             try {
884                 Flush();
885                 done = true;
886             } catch (CException& ex) {
887                 ERR_POST_X(9, ex);
888             }
889         }
890     }
891 }
892 
HandleIt(CDB_Exception * ex)893 bool CDB_UserHandler_Deferred::HandleIt(CDB_Exception* ex)
894 {
895     if (ex == NULL) {
896         return false;
897     }
898 
899     CFastMutexGuard LOCK(m_Mutex);
900     _TRACE(*ex);
901     m_SavedExceptions.push_back(ex->Clone());
902     return true;
903 }
904 
HandleAll(const TExceptions & exceptions)905 bool CDB_UserHandler_Deferred::HandleAll(const TExceptions& exceptions)
906 {
907     CFastMutexGuard LOCK(m_Mutex);
908     ITERATE (TExceptions, ex, exceptions) {
909         if (*ex == NULL) {
910             continue;
911         }
912         _TRACE(**ex);
913         m_SavedExceptions.push_back((*ex)->Clone());
914     }
915     return true;
916 }
917 
Flush(EDiagSev max_severity)918 void CDB_UserHandler_Deferred::Flush(EDiagSev max_severity)
919 {
920     CFastMutexGuard LOCK(m_Mutex);
921     ERASE_ITERATE (TExceptions, it, m_SavedExceptions) {
922         unique_ptr<CDB_Exception> ex(*it);
923         VECTOR_ERASE(it, m_SavedExceptions);
924         if (ex->GetSeverity() > max_severity) {
925             ex->SetSeverity(max_severity);
926         }
927         if (max_severity < eDiag_Error  ||  !m_SavedExceptions.empty() ) {
928             try {
929                 m_UltimateHandlers.PostMsg(ex.get());
930             } catch (CDB_Exception& ex2) {
931                 if (ex2.GetSeverity() > max_severity) {
932                     ex2.SetSeverity(max_severity);
933                 }
934                 ERR_POST_X(10, Severity(ex2.GetSeverity()) << ex2);
935             }
936         } else {
937             m_UltimateHandlers.PostMsg(ex.get());
938         }
939     }
940 }
941 
942 
943 ////////////////////////////////////////////////////////////////////////////////
944 //  CDB_UserHandler_Exception_ODBC::
945 //
946 
~CDB_UserHandler_Exception_ODBC(void)947 CDB_UserHandler_Exception_ODBC::~CDB_UserHandler_Exception_ODBC(void)
948 {
949 }
950 
951 bool
HandleIt(CDB_Exception * ex)952 CDB_UserHandler_Exception_ODBC::HandleIt(CDB_Exception* ex)
953 {
954     if (!ex)
955         return false;
956 
957     ex->Throw();
958 
959     return true;
960 }
961 
962 
963 END_NCBI_SCOPE
964 
965 
966