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