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