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