1 #ifndef CPPCORE__DBAPI__SIMPLE__SDBAPI_IMPL__HPP
2 #define CPPCORE__DBAPI__SIMPLE__SDBAPI_IMPL__HPP
3 
4 /* $Id: sdbapi_impl.hpp 557819 2018-02-21 18:47:17Z satskyse $
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:  Pavel Ivanov
30  *
31  * File Description:
32  *
33  */
34 
35 #include <corelib/ncbiobj.hpp>
36 #include <dbapi/dbapi.hpp>
37 
38 #include <dbapi/simple/sdbapi.hpp>
39 
40 BEGIN_NCBI_SCOPE
41 
42 class CConnHolder;
43 
44 class CSDB_UserHandler : public CDB_UserHandler_Exception
45 {
46 public:
CSDB_UserHandler(CConnHolder & conn)47     CSDB_UserHandler(CConnHolder& conn)
48         : m_Conn(conn)
49         { }
50     bool HandleMessage(int severity, int msgnum, const string& message);
51 
52 private:
53     CConnHolder& m_Conn;
54 };
55 
56 class CConnHolder : public CObject
57 {
58 public:
59     CConnHolder(IConnection* conn, const CSDB_ConnectionParam& params);
60     virtual ~CConnHolder(void);
61 
62     IConnection* GetConn(void) const;
63     void AddOpenRef(void);
64     void CloseRef(void);
65 
66     const CDB_Exception::SContext& GetContext(void) const;
67     void SetTimeout(const CTimeout& timeout);
68     void ResetTimeout(void);
69     const list<string>& GetPrintOutput(void) const;
70     void ResetPrintOutput();
71 
72 private:
73     CConnHolder(const CConnHolder&);
74     CConnHolder& operator= (const CConnHolder&);
75 
76     IConnection* m_Conn;
77     size_t       m_DefaultTimeout;
78     bool         m_HasCustomTimeout;
79     bool         m_ContinueAfterRaiserror;
80     Uint4        m_CntOpen;
81     list<string> m_PrintOutput;
82     CRef<CDB_Exception::SContext> m_Context;
83     CRef<CSDB_UserHandler> m_Handler;
84     CMutex       m_Mutex;
85 
86     friend class CSDB_UserHandler;
87 };
88 
89 class CDatabaseImpl : public CObject
90 {
91 public:
92     CDatabaseImpl(void);
93     CDatabaseImpl(const CDatabaseImpl& other);
94     ~CDatabaseImpl(void);
95 
96     void Connect(const CSDB_ConnectionParam& params);
97     bool IsOpen() const;
98     bool EverConnected() const;
99     void Close();
100 
101     IConnection* GetConnection(void);
102     void SetTimeout(const CTimeout& timeout);
103     void ResetTimeout(void);
104     const list<string>& GetPrintOutput(void) const;
105     void ResetPrintOutput();
106 
107     const CDB_Exception::SContext& GetContext(void) const;
108 
109 private:
110     CRef<CConnHolder>   m_Conn;
111     bool                m_IsOpen;
112     bool                m_EverConnected;
113 };
114 
115 
116 class CBulkInsertImpl : public CObject
117 {
118 public:
119     CBulkInsertImpl(CDatabaseImpl* db_impl,
120                     const string&  tableName,
121                     int            autoflush);
122     ~CBulkInsertImpl(void);
123 
124     void SetHints(CTempString hints);
125     void AddHint(IBulkInsert::EHints hint, unsigned int value);
126     void AddOrderHint(CTempString columns);
127 
128     void Bind(int col, ESDB_Type type);
129     void EndRow(void);
130     void Complete(void);
131 
132     void WriteNull(void);
133     template <class T>
134     void WriteVal(const T& val);
135 
136 private:
137     void x_CheckCanWrite(int col);
138     void x_CheckWriteStarted(void);
139 
140     const CDB_Exception::SContext& x_GetContext(void) const;
141 
142     CRef<CDatabaseImpl> m_DBImpl;
143     IBulkInsert*        m_BI;
144     vector<CVariant>    m_Cols;
145     int                 m_Autoflush;
146     int                 m_RowsWritten;
147     int                 m_ColsWritten;
148     bool                m_WriteStarted;
149 
150     CRef<CDB_Exception::SContext> m_Context;
151 };
152 
153 
154 class IQueryFieldBasis
155 {
156 public:
~IQueryFieldBasis()157     virtual ~IQueryFieldBasis() { }
158 
159     virtual const CVariant*                GetValue(void) const = 0;
160     virtual const CDB_Exception::SContext& x_GetContext(void) const = 0;
161 
162     virtual CNcbiOstream* GetOStream(size_t blob_size,
163                                      TBlobOStreamFlags flags) const;
164     virtual CBlobBookmark GetBookmark(void) const;
165 };
166 
167 class CRemoteQFB : public IQueryFieldBasis
168 {
169 public:
CRemoteQFB(CQueryImpl & query,unsigned int col_num)170     CRemoteQFB(CQueryImpl& query, unsigned int col_num)
171         : m_Query(query), m_ColNum(col_num)
172         { }
173 
174     const CVariant*                GetValue(void) const override;
175     const CDB_Exception::SContext& x_GetContext(void) const override;
176 
177     CNcbiOstream* GetOStream(size_t blob_size,
178                              TBlobOStreamFlags flags) const override;
179     CBlobBookmark GetBookmark(void) const override;
180 
181 private:
182     CQueryImpl&  m_Query;
183     unsigned int m_ColNum;
184 };
185 
186 class CLocalQFB : public IQueryFieldBasis
187 {
188 public:
CLocalQFB(CVariant * value,const CDB_Exception::SContext & context)189     CLocalQFB(CVariant* value, const CDB_Exception::SContext& context)
190         : m_Value(value), m_Context(new CDB_Exception::SContext(context))
191         { }
192 
GetValue(void) const193     const CVariant*                GetValue(void) const override
194         { return m_Value.get(); }
x_GetContext(void) const195     const CDB_Exception::SContext& x_GetContext(void) const override
196         { return *m_Context; }
197 
198 private:
199     unique_ptr<CVariant>                m_Value;
200     unique_ptr<CDB_Exception::SContext> m_Context;
201 };
202 
203 class CParamQFB : public CLocalQFB
204 {
205 public:
CParamQFB(CVariant * value,const CDB_Exception::SContext & context,ESP_ParamType param_type)206     CParamQFB(CVariant* value, const CDB_Exception::SContext& context,
207               ESP_ParamType param_type)
208         : CLocalQFB(value, context), m_ParamType(param_type)
209         { }
210 
GetParamType(void) const211     ESP_ParamType GetParamType(void) const         { return m_ParamType; }
SetParamType(ESP_ParamType type)212     void          SetParamType(ESP_ParamType type) { m_ParamType = type; }
213 
214 private:
215     ESP_ParamType m_ParamType;
216 };
217 
218 
219 class CQueryFieldImpl : public CObject
220 {
221 public:
222     CQueryFieldImpl(CQueryImpl* q, unsigned int col_num);
223     CQueryFieldImpl(CQueryImpl* q, CVariant* v, ESP_ParamType param_type);
224 
225     virtual CRef<CQueryFieldImpl> Detach(void);
226 
227     const CVariant* GetValue(void) const;
228     virtual CNcbiIstream& AsIStream(void) const;
229     virtual const vector<unsigned char>& AsVector(void) const;
230     virtual CNcbiOstream& GetOStream(size_t blob_size,
231                                      TBlobOStreamFlags flags) const;
232     virtual CBlobBookmark GetBookmark(void) const;
233 
234 protected:
235     friend class CQueryImpl;
236 
237     // Takes ownership of *qf.m_Basis!
238     CQueryFieldImpl(CQueryFieldImpl& qf);
239 
240     const CDB_Exception::SContext& x_GetContext(void) const;
241 
242     unique_ptr<IQueryFieldBasis> m_Basis;
243 };
244 
245 class CQueryBlobImpl : public CQueryFieldImpl
246 {
247 public:
248     CQueryBlobImpl(CQueryImpl* q, unsigned int col_num);
249     CQueryBlobImpl(CQueryImpl* q, CVariant* v, ESP_ParamType param_type);
250 
251     CRef<CQueryFieldImpl> Detach(void) override;
252 
253     CNcbiIstream& AsIStream(void) const override;
254     const vector<unsigned char>& AsVector(void) const override;
255     CNcbiOstream& GetOStream(size_t blob_size,
256                              TBlobOStreamFlags flags) const override;
257     CBlobBookmark GetBookmark(void) const override;
258 
259 private:
260     // Takes ownership of *qb.m_Basis!
261     CQueryBlobImpl(CQueryBlobImpl& qb);
262 
263     /// Vector to cache BLOB value
264     mutable vector<unsigned char>       m_Vector;
265     /// String to cache BLOB value
266     mutable string                      m_ValueForStream;
267     /// Stream to cache BLOB value
268     mutable unique_ptr<CNcbiIstrstream> m_IStream;
269     /// Stream to change BLOB value
270     mutable unique_ptr<CNcbiOstream>    m_OStream;
271 };
272 
273 struct SQueryRSMetaData : public CObject
274 {
275     typedef map<string, int> TColNumsMap;
276 
277     TColNumsMap       col_nums;
278     vector<string>    col_names;
279     vector<ESDB_Type> col_types;
280 
281     CConstRef<CDB_Exception::SContext> exception_context;
282 };
283 
284 class CQueryImpl: public CObject
285 {
286 public:
287     CQueryImpl(CDatabaseImpl* db_impl);
288     ~CQueryImpl(void);
289 
290     template <class T>
291     void SetParameter(CTempString name, const T& value, ESDB_Type type, ESP_ParamType param_type);
292     void SetNullParameter(CTempString name, ESDB_Type type, ESP_ParamType param_type);
293     const CQuery::CField& GetParameter(CTempString name);
294     void ClearParameter(CTempString name);
295     void ClearParameters(void);
296 
297     void SetSql(CTempString sql);
298     void Execute(const CTimeout& timeout);
299     void ExecuteSP(CTempString sp, const CTimeout& timeout);
300     void Cancel(void);
301     bool HasMoreResultSets(void);
302     void PurgeResults(void);
303     void BeginNewRS(void);
304     void Next(void);
305     void RequireRowCount(unsigned int min_rows, unsigned int max_rows);
306     void VerifyDone(CQuery::EHowMuch how_much = CQuery::eThisResultSet);
307     const CQuery::CRow& GetRow(void) const;
308     const CQuery::CField& GetColumn(const CDBParamVariant& col) const;
309     const CVariant& GetFieldValue(unsigned int col_num);
310     bool IsFinished(CQuery::EHowMuch how_much = CQuery::eThisResultSet) const;
311 
312     void SetIgnoreBounds(bool is_ignore);
313     unsigned int GetResultSetNo(void) const;
314     unsigned int GetRowNo(CQuery::EHowMuch how_much = CQuery::eAllResultSets) const;
315     int GetRowCount(void) const;
316     int GetStatus(void) const;
317     unsigned int GetTotalColumns(void) const;
318     string GetColumnName(unsigned int col) const;
319     ESDB_Type GetColumnType(unsigned int col) const;
320 
321     CDatabaseImpl* GetDatabase(void) const;
322     IConnection* GetConnection(void);
323 
324     const list<string>& GetPrintOutput(void) const;
325     // Historically private, but useful for CQuery's inner classes too.
326     const CDB_Exception::SContext& x_GetContext(void) const;
327 
GetMinRowCount(void) const328     unsigned int GetMinRowCount(void) const
329     { return m_MinRowCount; }
GetMaxRowCount(void) const330     unsigned int GetMaxRowCount(void) const
331     { return m_MaxRowCount; }
332 
333 private:
334     void x_CheckCanWork(bool need_rs = false) const;
335     void x_SetOutParameter(const string& name, const CVariant& value);
336     void x_ClearAllParams(void);
337     void x_CheckRowCount(void);
338     bool x_Fetch(void);
339     void x_InitBeforeExec(void);
340     void x_InitRSFields(void);
341     void x_DetachAllFields(void);
342     void x_Close(void);
343 
344 
345     typedef map<string, CQuery::CField>         TParamsMap;
346 
347     CRef<CDatabaseImpl> m_DBImpl;
348     IStatement*         m_Stmt;
349     ICallableStatement* m_CallStmt;
350     TParamsMap          m_Params;
351     string              m_Sql;
352     IResultSet*         m_CurRS;
353     bool                m_IgnoreBounds;
354     bool                m_HasExplicitMode;
355     bool                m_RSBeginned;
356     bool                m_RSFinished;
357     bool                m_Executed;
358     bool                m_ReportedWrongRowCount;
359     bool                m_IsSP;
360     bool                m_RowUnderConstruction;
361     unsigned int        m_CurRSNo;
362     unsigned int        m_CurRowNo;
363     unsigned int        m_CurRelRowNo;
364     unsigned int        m_MinRowCount;
365     unsigned int        m_MaxRowCount;
366     int                 m_RowCount;
367     int                 m_Status;
368     CQuery::CRow        m_Row;
369     mutable CRef<CDB_Exception::SContext> m_Context;
370 };
371 
372 
373 class CBlobBookmarkImpl : public CObject
374 {
375 public:
376     CBlobBookmarkImpl(CDatabaseImpl* db_impl, I_BlobDescriptor* descr);
377 
378     CNcbiOstream& GetOStream(size_t blob_size, TBlobOStreamFlags flags);
379 
380 private:
381     const CDB_Exception::SContext& x_GetContext(void) const;
382 
383     CRef<CDatabaseImpl> m_DBImpl;
384     unique_ptr<I_BlobDescriptor> m_Descr;
385     unique_ptr<CWStream> m_OStream;
386 };
387 
388 END_NCBI_SCOPE
389 
390 #endif  // CPPCORE__DBAPI__SIMPLE__SDBAPI_IMPL__HPP
391