1 #ifndef DBAPI_DRIVER___EXCEPTION__HPP
2 #define DBAPI_DRIVER___EXCEPTION__HPP
3 
4 /* $Id: exception.hpp 619521 2020-11-05 19:23:08Z grichenk $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Vladimir Soussov, Denis Vakatov
30  *
31  * File Description:  Exceptions
32  *
33  */
34 
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbiobj.hpp>
37 #include <corelib/ncbithr.hpp>
38 #include <corelib/ncbimtx.hpp>
39 
40 #include <deque>
41 
42 /** @addtogroup DbExceptions
43  *
44  * @{
45  */
46 
47 
48 BEGIN_NCBI_SCOPE
49 
50 class CDB_Object;
51 class CDBConnParams;
52 class CDBParams;
53 
54 BEGIN_SCOPE(impl)
55 class CConnection;
56 class CDBHandlerStack;
57 END_SCOPE(impl)
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 /// Helper macro for default database exception implementation.
61 #define NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(exception_class, base_class, db_err_code) \
62     { \
63         this->x_InitCDB(db_err_code); \
64     } \
65     exception_class(const exception_class& other) \
66        : base_class(other) \
67     { \
68         x_Assign(other); \
69     } \
70 public: \
71     virtual ~exception_class(void) throw() {} \
72     const char* GetType(void) const override {return #exception_class;} \
73     typedef int TErrCode; \
74     TErrCode GetErrCode(void) const \
75     { \
76         return typeid(*this) == typeid(exception_class) ? \
77             (TErrCode)x_GetErrCode() : (TErrCode)CException::eInvalid; \
78     } \
79     virtual CDB_Exception* Clone(void) const override \
80     { \
81         return new exception_class(*this); \
82     } \
83     NCBI_EXCEPTION_DEFAULT_THROW(exception_class) \
84 protected: \
85     exception_class(void) {} \
86     virtual const CException* x_Clone(void) const override \
87     { \
88         return new exception_class(*this); \
89     } \
90 private: \
91     /* for the sake of semicolon at the end of macro...*/ \
92     static void xx_unused_##exception_class(void)
93 
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 // DEPRECATED, Will be removed soon.
97 enum EDB_Severity {
98     eDB_Info,
99     eDB_Warning,
100     eDB_Error,
101     eDB_Fatal,
102     eDB_Unknown
103 };
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 ///
107 /// CDB_Exception --
108 ///
109 /// Define database exception.  CDB_Exception inherits its basic
110 /// functionality from CException and defines additional error codes for
111 /// databases.
112 
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 // class NCBI_DBAPIDRIVER_EXPORT CDB_Exception : public std::exception
116 class NCBI_DBAPIDRIVER_EXPORT CDB_Exception :
117     EXCEPTION_VIRTUAL_BASE public CException
118 {
119     friend class CDB_MultiEx;
120 
121 public:
122     /// Error types that can be generated.
123     enum EErrCode {
124         eDS,
125         eRPC,
126         eSQL,
127         eDeadlock,
128         eTimeout,
129         eClient,
130         eMulti,
131         eTruncate
132     };
133     typedef EErrCode EType;
134 
135     struct SParam {
136         string      name;
137         CDB_Object* value;
138     };
139     struct NCBI_DBAPIDRIVER_EXPORT SParams : public CObject {
140         ~SParams(void);
141 
142         typedef vector<SParam> TParams;
143         TParams params;
144     };
145 
146     struct NCBI_DBAPIDRIVER_EXPORT SContext : public CObject {
SContextCDB_Exception::SContext147         SContext() { }
148         SContext(const CDBConnParams& params);
149 
150         void UpdateFrom(const SContext& ctx);
151 
152         string server_name;
153         string username;
154         string database_name;
155         string extra_msg;
156     };
157 
158     struct NCBI_DBAPIDRIVER_EXPORT SMessageInContext {
SMessageInContextCDB_Exception::SMessageInContext159         SMessageInContext(const string& msg, const SContext& ctx)
160             :  message(msg), context(&ctx)
161             { }
SMessageInContextCDB_Exception::SMessageInContext162         SMessageInContext(const string& msg = kEmptyStr)
163             : message(msg)
164             { }
SMessageInContextCDB_Exception::SMessageInContext165         SMessageInContext(const char*   msg)
166             : message(msg)
167             { }
168 
169         SMessageInContext operator+(const SContext& ctx) const;
170 
171         string              message;
172         CConstRef<SContext> context;
173 
174     private:
175         friend class CDB_Exception;
176         friend class CSDB_Exception;
operator const string&CDB_Exception::SMessageInContext177         operator const string&(void) const { return message; }
178     };
179 
180     // access
181     // DEPRECATED, Will be removed soon.
182     NCBI_DEPRECATED
183     EDB_Severity        Severity(void) const;
GetDBErrCode(void) const184     int                 GetDBErrCode(void) const { return m_DBErrCode; }
185 
186     const char*         SeverityString(void) const;
187     // DEPRECATED, Will be removed soon.
188     NCBI_DEPRECATED
189     static const char*  SeverityString(EDB_Severity sev);
190     virtual const char* GetErrCodeString(void) const override;
191 
192 public:
193     // Duplicate methods. We need them to support the old interface.
194 
195     EType Type(void) const;
196     // text representation of the exception type and severity
TypeString() const197     virtual const char* TypeString() const { return GetType();         }
ErrCode(void) const198     int ErrCode(void) const { return GetDBErrCode();                   }
Message(void) const199     const string& Message(void) const { return GetMsg();               }
OriginatedFrom() const200     const string& OriginatedFrom() const { return GetModule();         }
201 
SetServerName(const string & sn)202     void SetServerName(const string& sn) { x_SetContext().server_name = sn; }
GetServerName(void) const203     const string& GetServerName(void) const { return m_Context->server_name; }
204 
SetUserName(const string & name)205     void SetUserName(const string& name) { x_SetContext().username = name; }
GetUserName(void) const206     const string& GetUserName(void) const { return m_Context->username; }
207 
SetDatabaseName(const string & d)208     void SetDatabaseName(const string& d) { x_SetContext().database_name = d; }
GetDatabaseName(void) const209     const string& GetDatabaseName(void) const
210         { return m_Context->database_name; }
211 
GetContext(void) const212     const SContext& GetContext(void) const { return *m_Context; }
ApplyContext(const SContext & ctx)213     void ApplyContext(const SContext& ctx)
214         { x_SetContext().UpdateFrom(ctx); }
215     void SetFromConnection(const impl::CConnection& connection);
216 
SetExtraMsg(const string & msg)217     void SetExtraMsg(const string& msg)   { x_SetContext().extra_msg = msg; }
GetExtraMsg(void) const218     const string& GetExtraMsg(void) const { return m_Context->extra_msg; }
219 
220     void SetParams(const CDBParams* params);
SetParams(const CDBParams & params)221     void SetParams(const CDBParams& params) { SetParams(&params); }
GetParams(void) const222     CConstRef<SParams> GetParams(void) const { return m_Params; }
223 
SetRowsInBatch(unsigned int n)224     void SetRowsInBatch(unsigned int n) { m_RowsInBatch = n; }
GetRowsInBatch(void) const225     unsigned int GetRowsInBatch(void) const { return m_RowsInBatch; }
226 
227 
228     /// WARNING !!! Sybase severity value can be provided by Sybase/FreeTDS
229     /// ctlib drivers only.
SetSybaseSeverity(int severity)230     void SetSybaseSeverity(int severity) { m_SybaseSeverity = severity;}
GetSybaseSeverity(void) const231     int GetSybaseSeverity(void) const { return m_SybaseSeverity;       }
232 
233 public:
234     virtual void ReportExtra(ostream& out) const override;
235     virtual CDB_Exception* Clone(void) const;
236 
237 public:
238     // Warning: exception constructor must be "public" because MSVC 7.1 won't
239     // catch parent exceptions other way.
240     CDB_Exception(const CDiagCompileInfo& info,
241                   const CException* prev_exception,
242                   EErrCode err_code,
243                   const SMessageInContext& message,
244                   EDiagSev severity,
245                   int db_err_code)
246         : CException(info,
247                      prev_exception,
248                      (CException::EErrCode)err_code,
249                      message.message,
250                      severity )
251         , m_DBErrCode(db_err_code)
252         , m_Context(message.context)
253         , m_SybaseSeverity(0)
254         , m_RowsInBatch(0)
255         NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_Exception, CException);
256 
257 public:
258     template<class E>
MakeException(const CDiagCompileInfo & info,const SMessageInContext & message,EDiagSev severity,int db_err_code)259     NCBI_NORETURN static void MakeException(const CDiagCompileInfo& info,
260         const SMessageInContext& message,
261         EDiagSev severity,
262         int db_err_code)
263     {
264         E ex(info, nullptr, message, severity, db_err_code);
265         if (severity == eDiag_Error || severity == eDiag_Fatal)
266             ex.SetRetriable(eRetriable_No);
267         else
268             ex.SetRetriable(eRetriable_Unknown);
269         throw ex;
270     }
271 
272 protected:
273     int     m_DBErrCode;
274 
275 protected:
276     void x_StartOfWhat(ostream& out) const;
277     void x_EndOfWhat  (ostream& out) const;
278     void x_Init(const CDiagCompileInfo& info, const string& message,
279                 const CException* prev_exception, EDiagSev severity) override;
280     virtual void x_Assign(const CException& src) override;
x_InitCDB(int db_error_code)281     void x_InitCDB(int db_error_code) { m_DBErrCode = db_error_code; }
282     SContext& x_SetContext(void);
283 
284 private:
285     CConstRef<SContext> m_Context;
286     int                 m_SybaseSeverity;
287     CRef<SParams>       m_Params;
288     unsigned int        m_RowsInBatch;
289 };
290 
291 inline
operator +(const string & msg,const CDB_Exception::SContext & ctx)292 CDB_Exception::SMessageInContext operator+(const string& msg,
293                                            const CDB_Exception::SContext& ctx)
294 {
295     return CDB_Exception::SMessageInContext(msg, ctx);
296 }
297 
298 inline
operator +(const char * msg,const CDB_Exception::SContext & ctx)299 CDB_Exception::SMessageInContext operator+(const char* msg,
300                                            const CDB_Exception::SContext& ctx)
301 {
302     return CDB_Exception::SMessageInContext(msg, ctx);
303 }
304 
305 NCBI_DBAPIDRIVER_EXPORT ostream& operator<<(ostream &os, const CDB_Exception::SContext& ctx);
306 NCBI_DBAPIDRIVER_EXPORT ostream& operator<<(ostream &os, const CDB_Exception::SMessageInContext& msg);
307 
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 class NCBI_DBAPIDRIVER_EXPORT CDB_DSEx : public CDB_Exception
311 {
312 public:
313     CDB_DSEx(const CDiagCompileInfo& info,
314              const CException* prev_exception,
315              const SMessageInContext& message,
316              EDiagSev severity,
317              int db_err_code)
318         : CDB_Exception(info, prev_exception,
319                         CDB_Exception::eDS,
320                         message, severity,
321                         db_err_code)
322         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_DSEx,
323                                                        CDB_Exception,
324                                                        db_err_code);
325 
326 };
327 
328 
329 ////////////////////////////////////////////////////////////////////////////////
330 class NCBI_DBAPIDRIVER_EXPORT CDB_RPCEx : public CDB_Exception
331 {
332 public:
333     CDB_RPCEx(const CDiagCompileInfo& info,
334               const CException* prev_exception,
335               const SMessageInContext& message,
336               EDiagSev severity,
337               int db_err_code,
338               const string& proc_name,
339               int proc_line)
340         : CDB_Exception(info,
341                         prev_exception,
342                         CDB_Exception::eRPC,
343                         message,
344                         severity,
345                         db_err_code)
346         , m_ProcName(proc_name.empty() ? "Unknown" : proc_name)
347         , m_ProcLine(proc_line)
348         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_RPCEx,
349                                                        CDB_Exception,
350                                                        db_err_code);
351 
352 public:
ProcName() const353     const string& ProcName()  const { return m_ProcName; }
ProcLine() const354     int           ProcLine()  const { return m_ProcLine; }
355 
356     virtual void ReportExtra(ostream& out) const override;
357 
358 protected:
359     virtual void x_Assign(const CException& src) override;
360 
361 private:
362     string m_ProcName;
363     int    m_ProcLine;
364 };
365 
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 class NCBI_DBAPIDRIVER_EXPORT CDB_SQLEx : public CDB_Exception
369 {
370 public:
371     CDB_SQLEx(const CDiagCompileInfo& info,
372               const CException* prev_exception,
373               const SMessageInContext& message,
374               EDiagSev severity,
375               int db_err_code,
376               const string& sql_state,
377               int batch_line)
378         : CDB_Exception(info,
379                         prev_exception,
380                         CDB_Exception::eSQL,
381                         message,
382                         severity,
383                         db_err_code)
384         , m_SqlState(sql_state.empty() ? "Unknown" : sql_state)
385         , m_BatchLine(batch_line)
386         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_SQLEx,
387                                                        CDB_Exception,
388                                                        db_err_code);
389 
390 public:
SqlState() const391     const string& SqlState()   const { return m_SqlState;  }
BatchLine() const392     int           BatchLine()  const { return m_BatchLine; }
393 
394     virtual void ReportExtra(ostream& out) const override;
395 
396 protected:
397     virtual void x_Assign(const CException& src) override;
398 
399 private:
400     string m_SqlState;
401     int    m_BatchLine;
402 };
403 
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 class NCBI_DBAPIDRIVER_EXPORT CDB_DeadlockEx : public CDB_Exception
407 {
408 public:
409     CDB_DeadlockEx(const CDiagCompileInfo& info,
410                    const CException* prev_exception,
411                    const SMessageInContext& message)
412        : CDB_Exception(info,
413                        prev_exception,
414                        CDB_Exception::eDeadlock,
415                        message,
416                        eDiag_Error,
417                        123456)
418         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_DeadlockEx,
419                                                        CDB_Exception,
420                                                        123456);
421 
422 };
423 
424 
425 ////////////////////////////////////////////////////////////////////////////////
426 class NCBI_DBAPIDRIVER_EXPORT CDB_TimeoutEx : public CDB_Exception
427 {
428 public:
429     CDB_TimeoutEx(const CDiagCompileInfo& info,
430                   const CException* prev_exception,
431                   const SMessageInContext& message,
432                   int db_err_code)
433        : CDB_Exception(info,
434                        prev_exception,
435                        CDB_Exception::eTimeout,
436                        message,
437                        eDiag_Error,
438                        db_err_code)
439         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_TimeoutEx,
440                                                        CDB_Exception,
441                                                        db_err_code);
442 };
443 
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 class NCBI_DBAPIDRIVER_EXPORT CDB_ClientEx : public CDB_Exception
447 {
448 public:
CDB_ClientEx(const CDiagCompileInfo & info,const CException * prev_exception,const SMessageInContext & message,EDiagSev severity,int db_err_code,const SContext & dbg_info,const impl::CConnection & connection,const CDBParams * params)449     CDB_ClientEx(const CDiagCompileInfo& info,
450                  const CException* prev_exception,
451                  const SMessageInContext& message,
452                  EDiagSev severity,
453                  int db_err_code,
454                  const SContext& dbg_info,
455                  const impl::CConnection& connection,
456                  const CDBParams* params)
457        : CDB_Exception(info, prev_exception, CDB_Exception::eClient,
458                        message + dbg_info, severity, db_err_code)
459     {
460         SetFromConnection(connection);
461         SetParams(params);
462     }
463     CDB_ClientEx(const CDiagCompileInfo& info,
464                  const CException* prev_exception,
465                  const SMessageInContext& message,
466                  EDiagSev severity,
467                  int db_err_code)
468        : CDB_Exception(info,
469                        prev_exception,
470                        CDB_Exception::eClient,
471                        message,
472                        severity,
473                        db_err_code)
474         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_ClientEx,
475                                                        CDB_Exception,
476                                                        db_err_code);
477 };
478 
479 
480 
481 ////////////////////////////////////////////////////////////////////////////////
482 class NCBI_DBAPIDRIVER_EXPORT CDB_TruncateEx : public CDB_Exception
483 {
484 public:
485     CDB_TruncateEx(const CDiagCompileInfo& info,
486                    const CException* prev_exception,
487                    const SMessageInContext& message,
488                    int db_err_code)
489        : CDB_Exception(info,
490                        prev_exception,
491                        CDB_Exception::eTruncate,
492                        message,
493                        eDiag_Warning,
494                        db_err_code)
495         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_TruncateEx,
496                                                        CDB_Exception,
497                                                        db_err_code);
498 };
499 
500 
501 
502 ////////////////////////////////////////////////////////////////////////////////
503 class NCBI_DBAPIDRIVER_EXPORT CDB_MultiEx : public CDB_Exception
504 {
505 public:
506     // ctor/dtor
507     CDB_MultiEx(const CDiagCompileInfo& info,
508                 const CException* prev_exception,
509                 unsigned int  capacity = 64)
510         : CDB_Exception(info,
511                         prev_exception,
512                         CDB_Exception::eMulti,
513                         kEmptyStr,
514                         eDiag_Info,
515                         0)
516         , m_Bag( new CObjectFor<TExceptionStack>() )
517         , m_NofRooms( capacity )
518         NCBI_DATABASE_EXCEPTION_DEFAULT_IMPLEMENTATION(CDB_MultiEx,
519                                                        CDB_Exception,
520                                                        0 );
521 
522 public:
523     bool              Push(const CDB_Exception& ex);
524     // REsult is not owned by CDB_MultiEx
525     CDB_Exception*    Pop(void);
526 
NofExceptions() const527     unsigned int NofExceptions() const {
528         return static_cast<unsigned int>( m_Bag->GetData().size() );
529     }
Capacity() const530     unsigned int Capacity()      const { return m_NofRooms;                 }
531 
532     string WhatThis(void) const;
533 
534     virtual void ReportExtra(ostream& out) const override;
535 
536 protected:
537     void ReportErrorStack(ostream& out) const;
538     virtual void x_Assign(const CException& src) override;
539 
540 private:
541     // We use "deque" instead of "stack" here we need to iterate over all
542     // recors in the container.
543     typedef deque<AutoPtr<const CDB_Exception> > TExceptionStack;
544 
545     CRef<CObjectFor<TExceptionStack> > m_Bag;
546     unsigned int m_NofRooms; ///< Max number of error messages to print..
547 };
548 
549 
550 
551 
552 /////////////////////////////////////////////////////////////////////////////
553 //
554 // CDB_UserHandler::   base class for user-defined handlers
555 //
556 //   Specializations of "CDB_UserHandler" -- to print error messages to:
557 //
558 // CDB_UserHandler_Default::   default destination (now:  CDB_UserHandler_Diag)
559 // CDB_UserHandler_Diag::      C++ Toolkit diagnostics
560 // CDB_UserHandler_Stream::    std::ostream specified by the user
561 //
562 
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler : public CObject
566 {
567 public:
568     CDB_UserHandler(void);
569     virtual ~CDB_UserHandler(void);
570 
571 public:
572     /// Exception container type
573     /// @sa HandleAll()
574     typedef deque<CDB_Exception*> TExceptions;
575     static void ClearExceptions(TExceptions& expts);
576 
577     /// Handle all of the exceptions resulting from a native API call.
578     /// @param exceptions
579     ///   List of exceptions
580     /// @return
581     ///   TRUE if the exceptions are handled -- in this case, HandleIt() methods
582     ///   will *NOT* be called.
583     /// @sa HandleIt(), CException::Throw()
584     virtual bool HandleAll(const TExceptions& exceptions);
585 
586     /// Handle the exceptions resulting from a native API call, one-by-one.
587     /// @return
588     ///   TRUE if "ex" is processed, FALSE if not (or if "ex" is NULL)
589     /// @sa HandleAll(), CException::Throw()
590     virtual bool HandleIt(CDB_Exception* ex) = 0;
591 
592     /// Handle message resulting from a native API call.
593     /// Method MUST NOT throw any exceptions.
594     ///
595     /// @return
596     ///   TRUE if message is processed and shouldn't be saved for later
597     ///   appearance as CDB_Exception, FALSE otherwise (default value is FALSE)
598     virtual bool HandleMessage(int severity, int msgnum, const string& message);
599 
600     // Get current global "last-resort" error handler.
601     // If not set, then the default will be "CDB_UserHandler_Default".
602     // This handler is guaranteed to be valid up to the program termination,
603     // and it will call the user-defined handler last set by SetDefault().
604     // NOTE:  never pass it to SetDefault, like:  "SetDefault(&GetDefault())"!
605     static CDB_UserHandler& GetDefault(void);
606 
607     // Alternate the default global "last-resort" error handler.
608     // Passing NULL will mean to ignore all errors that reach it.
609     // Return previously set (or default-default if not set yet) handler.
610     // The returned handler should be delete'd by the caller; the last set
611     // handler will be delete'd automagically on the program termination.
612     static CDB_UserHandler* SetDefault(CDB_UserHandler* h);
613 
614     /// Method is deprecated. Use CDB_Exception::GetExtraMsg() instead.
615     NCBI_DEPRECATED string GetExtraMsg(void) const;
616     /// Method is deprecated. Use CDB_Exception::SetExtraMsg() instead.
617     NCBI_DEPRECATED void SetExtraMsg(const string& msg) const;
618 
619 protected:
620     /// Simply call HandleIt on each exception.
621     bool x_HandleAll(const TExceptions& exceptions);
622 };
623 
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler_Diag : public CDB_UserHandler
627 {
628 public:
629     CDB_UserHandler_Diag(const string& prefix = kEmptyStr);
630     virtual ~CDB_UserHandler_Diag();
631 
632     // Print "*ex" to the standard C++ Toolkit diagnostics, with "prefix".
633     // Always return TRUE (i.e. always process the "ex").
634     virtual bool HandleIt(CDB_Exception* ex);
635 
636     virtual bool HandleAll(const TExceptions& exceptions);
637 
638 private:
639     string m_Prefix;     // string to prefix each message with
640 };
641 
642 
643 ////////////////////////////////////////////////////////////////////////////////
644 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler_Stream : public CDB_UserHandler
645 {
646 public:
647     CDB_UserHandler_Stream(ostream*      os     = 0 /*cerr*/,
648                            const string& prefix = kEmptyStr,
649                            bool          own_os = false);
650     virtual ~CDB_UserHandler_Stream();
651 
652     // Print "*ex" to the output stream "os", with "prefix" (as set by  c-tor).
653     // Return TRUE (i.e. process the "ex") unless write to "os" failed.
654     virtual bool HandleIt(CDB_Exception* ex);
655 
656     virtual bool HandleAll(const TExceptions& exceptions);
657 
658 private:
659     mutable CFastMutex  m_Mtx;
660 
661     ostream* m_Output;     // output stream to print messages to
662     string   m_Prefix;     // string to prefix each message with
663     bool     m_OwnOutput;  // if TRUE, then delete "m_Output" in d-tor
664 };
665 
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler_Exception :
669     public CDB_UserHandler
670 {
671 public:
672     virtual ~CDB_UserHandler_Exception(void);
673 
674     virtual bool HandleIt(CDB_Exception* ex);
675     virtual bool HandleAll(const TExceptions& exceptions);
676 };
677 
678 
679 ////////////////////////////////////////////////////////////////////////////////
680 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler_Deferred : public CDB_UserHandler
681 {
682 public:
683     CDB_UserHandler_Deferred(const impl::CDBHandlerStack& ultimate_handlers);
684     ~CDB_UserHandler_Deferred(void);
685 
686     bool HandleIt(CDB_Exception* ex);
687     bool HandleAll(const TExceptions& exceptions);
688 
689     void Flush(EDiagSev max_severity = eDiagSevMax);
690 
691 private:
692     TExceptions                  m_SavedExceptions;
693     const impl::CDBHandlerStack& m_UltimateHandlers;
694     CFastMutex                   m_Mutex;
695 };
696 
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 class NCBI_DBAPIDRIVER_EXPORT CDB_UserHandler_Exception_ODBC :
700     public CDB_UserHandler
701 {
702 public:
703     virtual ~CDB_UserHandler_Exception_ODBC(void);
704 
705     virtual bool HandleIt(CDB_Exception* ex);
706 };
707 
708 
709 ////////////////////////////////////////////////////////////////////////////////
710 typedef CDB_UserHandler_Diag CDB_UserHandler_Default;
711 
712 ////////////////////////////////////////////////////////////////////////////////
713 /// Generic macro to throw a database exception, given the exception class,
714 /// database error code and message string.
715 #define NCBI_DATABASE_THROW( exception_class, message, err_code, severity ) \
716     do { \
717         NCBI_NS_NCBI::CDB_Exception::MakeException<exception_class>( \
718             DIAG_COMPILE_INFO, (message), severity, err_code); \
719     } while(0)
720 #define NCBI_DATABASE_RETHROW( prev_exception, exception_class, message, \
721     err_code, severity ) \
722     throw exception_class( DIAG_COMPILE_INFO, \
723         &(prev_exception), (message), severity, err_code )
724 
725 // Driver code typically redefines NCBI_DATABASE_(RE)THROW in terms of these.
726 #define NCBI_DATABASE_THROW_ANNOTATED(ex_class, message, err_code, severity, \
727                                       dbg_info, conn, params) \
728     do { \
729         ex_class ex(DIAG_COMPILE_INFO, NULL, (message), severity, err_code, \
730                     dbg_info, conn, params); \
731         ex.SetRetriable(eRetriable_No); \
732         throw ex; \
733     } while (0)
734 
735 #define NCBI_DATABASE_RETHROW_ANNOTATED(prev_ex, ex_class, message, err_code, \
736                                         severity, dbg_info, conn, params) \
737     throw ex_class(DIAG_COMPILE_INFO, &(prev_ex), (message), severity, \
738                    err_code, dbg_info, conn, params)
739 
740 #define DATABASE_DRIVER_ERROR( message, err_code ) \
741     NCBI_DATABASE_THROW( CDB_ClientEx, message, err_code, eDiag_Error )
742 #define DATABASE_DRIVER_ERROR_EX( prev_exception, message, err_code ) \
743     NCBI_DATABASE_RETHROW( prev_exception, CDB_ClientEx, message, err_code, \
744     eDiag_Error )
745 
746 #define DATABASE_DRIVER_WARNING( message, err_code ) \
747     NCBI_DATABASE_THROW( CDB_ClientEx, message, err_code, eDiag_Warning )
748 #define DATABASE_DRIVER_WARNING_EX( prev_exception, message, err_code ) \
749     NCBI_DATABASE_RETHROW( prev_exception, CDB_ClientEx, message, err_code, \
750     eDiag_Warning )
751 
752 #define DATABASE_DRIVER_FATAL( message, err_code ) \
753     NCBI_DATABASE_THROW( CDB_ClientEx, message, err_code, eDiag_Fatal )
754 #define DATABASE_DRIVER_FATAL_EX( prev_exception, message, err_code ) \
755     NCBI_DATABASE_RETHROW( prev_exception, CDB_ClientEx, message, err_code, \
756     eDiag_Fatal )
757 
758 #define DATABASE_DRIVER_INFO( message, err_code ) \
759     NCBI_DATABASE_THROW( CDB_ClientEx, message, err_code, eDiag_Info )
760 #define DATABASE_DRIVER_INFO_EX( prev_exception, message, err_code ) \
761     NCBI_DATABASE_RETHROW( prev_exception, CDB_ClientEx, message, err_code, \
762     eDiag_Info )
763 
764 
765 #define CHECK_DRIVER_ERROR( failed, message, err_code ) \
766     if ( ( failed ) ) { DATABASE_DRIVER_ERROR( message, err_code ); }
767 
768 #define CHECK_DRIVER_WARNING( failed, message, err_code ) \
769     if ( ( failed ) ) { DATABASE_DRIVER_WARNING( message, err_code ); }
770 
771 #define CHECK_DRIVER_FATAL( failed, message, err_code ) \
772     if ( ( failed ) ) { DATABASE_DRIVER_FATAL( message, err_code ); }
773 
774 #define CHECK_DRIVER_INFO( failed, message, err_code ) \
775     if ( ( failed ) ) { DATABASE_DRIVER_INFO( message, err_code ); }
776 
777 END_NCBI_SCOPE
778 
779 
780 /* @} */
781 
782 
783 #endif  /* DBAPI_DRIVER___EXCEPTION__HPP */
784