1 /* $Id: stmt_impl.cpp 633350 2021-06-16 19:23:57Z ivanov $
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 * File Name:  $Id: stmt_impl.cpp 633350 2021-06-16 19:23:57Z ivanov $
27 *
28 * Author:  Michael Kholodov
29 *
30 * File Description:  Statement implementation
31 *
32 *
33 *
34 *
35 */
36 
37 #include <ncbi_pch.hpp>
38 #include "conn_impl.hpp"
39 #include "stmt_impl.hpp"
40 #include "rs_impl.hpp"
41 #include "rw_impl.hpp"
42 #include <dbapi/driver/public.hpp>
43 #include <dbapi/error_codes.hpp>
44 
45 
46 #define NCBI_USE_ERRCODE_X   Dbapi_ObjImpls
47 
48 
49 BEGIN_NCBI_SCOPE
50 
51 ////////////////////////////////////////////////////////////////////////////////
CStmtParamsMetaData(I_BaseCmd * & cmd)52 CStatement::CStmtParamsMetaData::CStmtParamsMetaData(I_BaseCmd*& cmd)
53 : m_Cmd(cmd)
54 {
55 }
56 
~CStmtParamsMetaData()57 CStatement::CStmtParamsMetaData::~CStmtParamsMetaData()
58 {
59 }
60 
61 
GetTotalColumns() const62 unsigned int CStatement::CStmtParamsMetaData::GetTotalColumns() const
63 {
64     _ASSERT(m_Cmd);
65     return m_Cmd->GetBindParams().GetNum();
66 }
67 
GetType(const CDBParamVariant & param) const68 EDB_Type CStatement::CStmtParamsMetaData::GetType(const CDBParamVariant& param) const
69 {
70     _ASSERT(m_Cmd);
71     return m_Cmd->GetBindParams().GetDataType(param);
72 }
73 
GetMaxSize(const CDBParamVariant & param) const74 int CStatement::CStmtParamsMetaData::GetMaxSize(const CDBParamVariant& param) const
75 {
76     _ASSERT(m_Cmd);
77     return m_Cmd->GetBindParams().GetDataType(param);
78 }
79 
GetName(const CDBParamVariant & param) const80 string CStatement::CStmtParamsMetaData::GetName(const CDBParamVariant& param) const
81 {
82     _ASSERT(m_Cmd);
83     return m_Cmd->GetBindParams().GetName(param);
84 }
85 
GetDirection(const CDBParamVariant & param) const86 CDBParams::EDirection CStatement::CStmtParamsMetaData::GetDirection(const CDBParamVariant& param) const
87 {
88     _ASSERT(m_Cmd);
89     return m_Cmd->GetBindParams().GetDirection(param);
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 // implementation
CStatement(CConnection * conn)94 CStatement::CStatement(CConnection* conn)
95 : m_conn(conn)
96 , m_cmd(NULL)
97 , m_InParams(m_cmd)
98 , m_rowCount(-1)
99 , m_failed(false)
100 , m_irs(0)
101 , m_wr(0)
102 , m_ostr(0)
103 , m_AutoClearInParams(false)
104 {
105     SetIdent("CStatement");
106 }
107 
~CStatement()108 CStatement::~CStatement()
109 {
110     try {
111         Notify(CDbapiClosedEvent(this));
112         FreeResources();
113         Notify(CDbapiDeletedEvent(this));
114         _TRACE(GetIdent() << " " << (void*)this << " deleted.");
115     }
116     NCBI_CATCH_ALL_X( 9, kEmptyStr )
117 }
118 
GetParentConn()119 IConnection* CStatement::GetParentConn()
120 {
121     return m_conn;
122 }
123 
CacheResultSet(CDB_Result * rs)124 void CStatement::CacheResultSet(CDB_Result *rs)
125 {
126     if( m_irs != 0 ) {
127         _TRACE("CStatement::CacheResultSet(): Invalidating cached CResultSet " << (void*)m_irs);
128         m_irs->Invalidate();
129     }
130 
131     if( rs != 0 ) {
132         m_irs = new CResultSet(m_conn, rs);
133         m_irs->AddListener(this);
134         AddListener(m_irs);
135         _TRACE("CStatement::CacheResultSet(): Created new CResultSet " << (void*)m_irs
136             << " with CDB_Result " << (void*)rs);
137     } else {
138         m_irs = 0;
139     }
140 }
141 
GetResultSet()142 IResultSet* CStatement::GetResultSet()
143 {
144    return m_irs;
145 }
146 
HasMoreResults()147 bool CStatement::HasMoreResults()
148 {
149     // This method may be called even before *execute*.
150     // We have to be prepared for everything.
151     bool more = (GetBaseCmd() != NULL);
152 
153     if (more) {
154         more = GetBaseCmd()->HasMoreResults();
155         if( more ) {
156             if( GetBaseCmd()->HasFailed() ) {
157                 SetFailed(true);
158                 return false;
159             }
160             //Notify(CDbapiNewResultEvent(this));
161             CDB_Result *rs = GetBaseCmd()->Result();
162             CacheResultSet(rs);
163 #if 0
164             if( rs == 0 ) {
165                 m_rowCount = GetBaseCmd()->RowCount();
166             }
167 #endif
168         }
169     }
170 
171     return more;
172 }
173 
SetParam(const CVariant & v,const CDBParamVariant & param)174 void CStatement::SetParam(const CVariant& v,
175                           const CDBParamVariant& param)
176 {
177     if (param.IsPositional()) {
178         if (!m_params.empty()) {
179             NCBI_DBAPI_THROW("Binding by position is prohibited if any parameter was bound by name.");
180         }
181         if (m_posParams.size() < param.GetPosition())
182             m_posParams.resize(param.GetPosition());
183         CVariant*& var = m_posParams[param.GetPosition() - 1];
184         if (var)
185             *var = v;
186         else
187             var = new CVariant(v);
188     } else {
189         if (!m_posParams.empty()) {
190             NCBI_DBAPI_THROW("Binding by name is prohibited if any parameter was bound by position.");
191         }
192         const string name = param.GetName();
193         ParamList::iterator i = m_params.find(name);
194         if( i != m_params.end() ) {
195             *((*i).second) = v;
196         }
197         else {
198             m_params.insert(make_pair(name, new CVariant(v)));
199         }
200     }
201 }
202 
203 
ClearParamList()204 void CStatement::ClearParamList()
205 {
206     for(ParamList::iterator i = m_params.begin(); i != m_params.end(); ++i ) {
207         delete (*i).second;
208     }
209     for(ParamByPosList::iterator i = m_posParams.begin(); i != m_posParams.end(); ++i ) {
210         delete (*i);
211     }
212 
213     m_params.clear();
214     m_posParams.clear();
215 }
216 
Execute(const string & sql)217 void CStatement::Execute(const string& sql)
218 {
219     x_Send(sql);
220 }
221 
SendSql(const string & sql)222 void CStatement::SendSql(const string& sql)
223 {
224     x_Send(sql);
225 }
226 
x_Send(const string & sql)227 void CStatement::x_Send(const string& sql)
228 {
229     if( m_cmd != 0 ) {
230         delete m_cmd;
231         m_cmd = 0;
232         m_rowCount = -1;
233     }
234 
235     SetFailed(false);
236 
237     m_cmd = m_conn->GetCDB_Connection()->LangCmd(sql);
238 
239     ExecuteLast();
240 
241     if ( IsAutoClearInParams() ) {
242         // Implicitely clear all parameters.
243         ClearParamList();
244     }
245 }
246 
ExecuteQuery(const string & sql)247 IResultSet* CStatement::ExecuteQuery(const string& sql)
248 {
249     SendSql(sql);
250 
251     while ( HasMoreResults() ) {
252         if ( HasRows() ) {
253             return GetResultSet();
254         } else if ( Failed() ) {
255             NCBI_DBAPI_THROW("Query failed: " + sql);
256         }
257     }
258 
259     return 0;
260 }
ExecuteUpdate(const string & sql)261 void CStatement::ExecuteUpdate(const string& sql)
262 {
263     SendSql(sql);
264 
265     PurgeResults();
266 }
267 
ExecuteLast()268 void CStatement::ExecuteLast()
269 {
270     for(ParamList::iterator i = m_params.begin(); i != m_params.end(); ++i ) {
271         GetLangCmd()->GetBindParams().Bind((*i).first, (*i).second->GetData());
272     }
273     for(unsigned int i = 0; i < m_posParams.size(); ++i) {
274         CVariant* var = m_posParams[i];
275         if (!var) {
276             NCBI_DBAPI_THROW("Not all parameters were bound by position.");
277         }
278         GetLangCmd()->GetBindParams().Bind(i, var->GetData());
279     }
280     m_cmd->Send();
281 }
282 
283 const IResultSetMetaData&
GetParamsMetaData(void)284 CStatement::GetParamsMetaData(void)
285 {
286     return m_InParams;
287 }
288 
HasRows()289 bool CStatement::HasRows()
290 {
291     return m_irs != 0;
292 }
293 
GetBlobWriter(I_BlobDescriptor & d,size_t blob_size,TBlobOStreamFlags flags)294 IWriter* CStatement::GetBlobWriter(I_BlobDescriptor &d, size_t blob_size,
295                                    TBlobOStreamFlags flags)
296 {
297     delete m_wr;
298     m_wr = 0;
299     m_wr = new CxBlobWriter(GetConnection()->GetCDB_Connection(),
300                             d, blob_size, flags, false);
301     return m_wr;
302 }
303 
GetBlobOStream(I_BlobDescriptor & d,size_t blob_size,TBlobOStreamFlags flags,size_t buf_size)304 CNcbiOstream& CStatement::GetBlobOStream(I_BlobDescriptor &d, size_t blob_size,
305                                          TBlobOStreamFlags flags,
306                                          size_t buf_size)
307 {
308     delete m_ostr;
309     m_ostr = 0;
310     m_ostr = new CWStream(new CxBlobWriter(GetConnection()->GetCDB_Connection(),
311                                            d, blob_size, flags, false),
312                           buf_size, 0, (CRWStreambuf::fOwnWriter |
313                                         CRWStreambuf::fLogExceptions));
314     return *m_ostr;
315 }
316 
GetCDB_Result()317 CDB_Result* CStatement::GetCDB_Result()
318 {
319     return m_irs == 0 ? 0 : m_irs->GetCDB_Result();
320 }
321 
Failed()322 bool CStatement::Failed()
323 {
324     return m_failed;
325 }
326 
GetRowCount()327 int CStatement::GetRowCount()
328 {
329     int v;
330 
331     if( (v = GetBaseCmd()->RowCount()) >= 0 ) {
332         m_rowCount = v;
333     }
334 
335     return m_rowCount;
336 }
337 
Close()338 void CStatement::Close()
339 {
340     Notify(CDbapiClosedEvent(this));
341     FreeResources();
342 }
343 
FreeResources()344 void CStatement::FreeResources()
345 {
346     delete m_cmd;
347     m_cmd = 0;
348     m_rowCount = -1;
349 
350     if ( m_conn != 0 && m_conn->IsAux() ) {
351         delete m_conn;
352         m_conn = 0;
353         Notify(CDbapiAuxDeletedEvent(this));
354     }
355 
356     delete m_wr;
357     m_wr = 0;
358     delete m_ostr;
359     m_ostr = 0;
360 
361     ClearParamList();
362 }
363 
PurgeResults()364 void CStatement::PurgeResults()
365 {
366     while (HasMoreResults())
367     {
368         if (HasRows()) {
369             unique_ptr<IResultSet> rs( GetResultSet() );
370             m_irs = nullptr;
371             if (rs.get()) {
372                 // Is it necessary???
373                 while (rs->Next()) {
374                     ;
375                 }
376             }
377         }
378     }
379 }
380 
Cancel()381 void CStatement::Cancel()
382 {
383     if( GetBaseCmd() != 0 )
384         GetBaseCmd()->Cancel();
385 
386     m_rowCount = -1;
387 }
388 
GetLangCmd()389 CDB_LangCmd* CStatement::GetLangCmd()
390 {
391     //if( m_cmd == 0 )
392     //throw CDbException("CStatementImpl::GetLangCmd(): no cmd structure");
393     return (CDB_LangCmd*)m_cmd;
394 }
395 
Action(const CDbapiEvent & e)396 void CStatement::Action(const CDbapiEvent& e)
397 {
398     _TRACE(GetIdent() << " " << (void*)this << ": '" << e.GetName()
399            << "' received from " << e.GetSource()->GetIdent());
400 
401     CResultSet *rs;
402 
403     if (dynamic_cast<const CDbapiFetchCompletedEvent*>(&e) != 0 ) {
404         if( m_irs != 0 && (rs = dynamic_cast<CResultSet*>(e.GetSource())) != 0 ) {
405             if( rs == m_irs ) {
406                 m_rowCount = rs->GetTotalRows();
407                 _TRACE("Rowcount from the last resultset: " << m_rowCount);
408             }
409         }
410     }
411 
412     if (dynamic_cast<const CDbapiDeletedEvent*>(&e) != 0 ) {
413         RemoveListener(e.GetSource());
414         if(dynamic_cast<CConnection*>(e.GetSource()) != 0 ) {
415             _TRACE("Deleting " << GetIdent() << " " << (void*)this);
416             delete this;
417         }
418         else if( m_irs != 0 && (rs = dynamic_cast<CResultSet*>(e.GetSource())) != 0 ) {
419             if( rs == m_irs ) {
420                 _TRACE("Clearing cached CResultSet " << (void*)m_irs);
421                 m_irs = 0;
422             }
423         }
424     }
425 }
426 
427 END_NCBI_SCOPE
428