1//
2// Statement.cpp
3//
4// Library: SQL
5// Package: SQLCore
6// Module: Statement
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/SQL/Statement.h"
16#include "Poco/SQL/SQLException.h"
17#include "Poco/SQL/Extraction.h"
18#include "Poco/SQL/Session.h"
19#include "Poco/SQL/Bulk.h"
20#include "Poco/Any.h"
21#include "Poco/Tuple.h"
22#include "Poco/ActiveMethod.h"
23#include <algorithm>
24
25
26namespace Poco {
27namespace SQL {
28
29
30Statement::Statement(StatementImpl::Ptr pImpl):
31 _pImpl(pImpl),
32 _async(false)
33{
34 poco_check_ptr (pImpl);
35}
36
37
38Statement::Statement(Session& rSession):
39 _async(false)
40{
41 reset(rSession);
42}
43
44
45Statement::Statement(const Statement& stmt)
46{
47 if (stmt.isAsync() && !stmt.done()) wait();
48 _pImpl = stmt._pImpl;
49 _async = stmt._async;
50 _pResult = stmt._pResult;
51 _pAsyncExec = stmt._pAsyncExec;
52 _arguments = stmt._arguments;
53 _pRowFormatter = stmt._pRowFormatter;
54}
55
56
57Statement::Statement(Statement&& stmt)
58{
59 this->move(std::move(stmt));
60}
61
62
63Statement::~Statement()
64{
65}
66
67
68Statement& Statement::operator = (const Statement& stmt)
69{
70 if (stmt.isAsync() && !stmt.done()) stmt.wait();
71 if (this != &stmt)
72 {
73 Statement tmp(stmt);
74 swap(tmp);
75 }
76 return *this;
77}
78
79
80void Statement::swap(Statement& other)
81{
82 using std::swap;
83 if (this != &other)
84 {
85 swap(_pImpl, other._pImpl);
86 swap(_async, other._async);
87 swap(_pAsyncExec, other._pAsyncExec);
88 swap(_pResult, other._pResult);
89 _arguments.swap(other._arguments);
90 swap(_pRowFormatter, other._pRowFormatter);
91 }
92}
93
94
95Statement& Statement::operator = (Statement&& stmt)
96{
97 this->move(std::move(stmt));
98 return *this;
99}
100
101
102void Statement::move(Statement&& stmt)
103{
104 if (stmt.isAsync() && !stmt.done()) stmt.wait();
105 _pImpl = stmt._pImpl; stmt._pImpl = nullptr;
106 _async = stmt._async; stmt._async = false;
107 _pResult = stmt._pResult; stmt._pResult = nullptr;
108 _pAsyncExec = stmt._pAsyncExec; stmt._pAsyncExec = nullptr;
109 _arguments = std::move(stmt._arguments); stmt._arguments.clear();
110 _pRowFormatter = stmt._pRowFormatter; stmt._pRowFormatter = nullptr;
111}
112
113
114Statement& Statement::reset(Session& rSession)
115{
116 Statement stmt(rSession.createStatementImpl());
117 swap(stmt);
118 return *this;
119}
120
121
122std::size_t Statement::execute(bool doReset)
123{
124 Mutex::ScopedLock lock(_mutex);
125 bool isDone = done();
126 if (initialized() || paused() || isDone)
127 {
128 if (_arguments.size())
129 {
130 _pImpl->formatSQL(_arguments);
131 _arguments.clear();
132 }
133
134 if (!isAsync())
135 {
136 if (isDone) _pImpl->reset();
137 return _pImpl->execute(doReset);
138 }
139 else
140 {
141 doAsyncExec();
142 return 0;
143 }
144 }
145 else throw InvalidAccessException("Statement still executing.");
146}
147
148
149const Statement::Result& Statement::executeAsync(bool doReset)
150{
151 Mutex::ScopedLock lock(_mutex);
152 if (initialized() || paused() || done())
153 return doAsyncExec(doReset);
154 else
155 throw InvalidAccessException("Statement still executing.");
156}
157
158
159const Statement::Result& Statement::doAsyncExec(bool doReset)
160{
161 if (done()) _pImpl->reset();
162 if (!_pAsyncExec)
163 _pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute);
164 _pResult = new Result((*_pAsyncExec)(doReset));
165 return *_pResult;
166}
167
168
169void Statement::setAsync(bool async)
170{
171 _async = async;
172 if (_async && !_pAsyncExec)
173 _pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute);
174}
175
176
177std::size_t Statement::wait(long milliseconds) const
178{
179 if (!_pResult) return 0;
180 bool success = true;
181 if (WAIT_FOREVER != milliseconds)
182 success = _pResult->tryWait(milliseconds);
183 else
184 _pResult->wait();
185
186 if (_pResult->exception())
187 throw *_pResult->exception();
188 else if (!success)
189 throw TimeoutException("Statement timed out.");
190
191 return _pResult->data();
192}
193
194
195const std::string& Statement::getStorage() const
196{
197 switch (storage())
198 {
199 case STORAGE_VECTOR:
200 return StatementImpl::VECTOR;
201 case STORAGE_LIST:
202 return StatementImpl::LIST;
203 case STORAGE_DEQUE:
204 return StatementImpl::DEQUE;
205 case STORAGE_UNKNOWN:
206 return StatementImpl::UNKNOWN;
207 }
208
209 throw IllegalStateException("Invalid storage setting.");
210}
211
212
213Statement& Statement::operator , (Manipulator manip)
214{
215 manip(*this);
216 return *this;
217}
218
219
220Statement& Statement::addBind(AbstractBinding::Ptr pBind)
221{
222 if (pBind->isBulk())
223 {
224 if (!_pImpl->isBulkSupported())
225 throw InvalidAccessException("Bulk not supported by this session.");
226
227 if(_pImpl->bulkBindingAllowed())
228 _pImpl->setBulkBinding();
229 else
230 throw InvalidAccessException("Bulk and non-bulk binding modes can not be mixed.");
231 }
232 else _pImpl->forbidBulk();
233
234 _pImpl->addBind(pBind);
235 return *this;
236}
237
238
239Statement& Statement::addExtract(AbstractExtraction::Ptr pExtract)
240{
241 if (pExtract->isBulk())
242 {
243 if (!_pImpl->isBulkSupported())
244 throw InvalidAccessException("Bulk not supported by this session.");
245
246 if(_pImpl->bulkExtractionAllowed())
247 {
248 Bulk b(pExtract->getLimit());
249 _pImpl->setBulkExtraction(b);
250 }
251 else
252 throw InvalidAccessException("Bulk and non-bulk extraction modes can not be mixed.");
253 }
254 else _pImpl->forbidBulk();
255
256 _pImpl->addExtract(pExtract);
257 return *this;
258}
259
260
261Statement& Statement::operator , (const Limit& extrLimit)
262{
263 if (_pImpl->isBulkExtraction() && _pImpl->extractionLimit() != extrLimit)
264 throw InvalidArgumentException("Limit for bulk extraction already set.");
265
266 _pImpl->setExtractionLimit(extrLimit);
267 return *this;
268}
269
270
271Statement& Statement::operator , (const Range& extrRange)
272{
273 if (_pImpl->isBulkExtraction())
274 throw InvalidAccessException("Can not set range for bulk extraction.");
275
276 _pImpl->setExtractionLimit(extrRange.lower());
277 _pImpl->setExtractionLimit(extrRange.upper());
278 return *this;
279}
280
281
282Statement& Statement::operator , (const Bulk& bulk)
283{
284 if (!_pImpl->isBulkSupported())
285 throw InvalidAccessException("Bulk not supported by this session.");
286
287 if (0 == _pImpl->extractions().size() &&
288 0 == _pImpl->bindings().size() &&
289 _pImpl->bulkExtractionAllowed() &&
290 _pImpl->bulkBindingAllowed())
291 {
292 _pImpl->setBulkExtraction(bulk);
293 _pImpl->setBulkBinding();
294 }
295 else
296 throw InvalidAccessException("Can not set bulk operations.");
297
298 return *this;
299}
300
301
302Statement& Statement::operator , (BulkFnType)
303{
304 const Limit& limit(_pImpl->extractionLimit());
305 if (limit.isHardLimit() ||
306 limit.isLowerLimit() ||
307 Limit::LIMIT_UNLIMITED == limit.value())
308 {
309 throw InvalidAccessException("Bulk is only allowed with limited extraction,"
310 "non-hard and zero-based limits.");
311 }
312
313 Bulk bulk(limit);
314 _pImpl->setBulkExtraction(bulk);
315 _pImpl->setBulkBinding();
316
317 return *this;
318}
319
320
321Session Statement::session()
322{
323 Poco::AutoPtr<SessionImpl> ps(&impl()->session(), true);
324 return Session(ps);
325}
326
327
328void Statement::setTotalRowCount(const std::string& sql)
329{
330 std::size_t count;
331 session() << sql,
332 Poco::SQL::Keywords::into(count),
333 Poco::SQL::Keywords::now;
334 _pImpl->setTotalRowCount(count);
335}
336
337
338} } // namespace Poco::SQL
339