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 | |
26 | namespace Poco { |
27 | namespace Data { |
28 | |
29 | |
30 | Statement::Statement(StatementImpl::Ptr pImpl): |
31 | _pImpl(pImpl), |
32 | _async(false) |
33 | { |
34 | poco_check_ptr (pImpl); |
35 | } |
36 | |
37 | |
38 | Statement::Statement(Session& rSession): |
39 | _async(false) |
40 | { |
41 | reset(rSession); |
42 | } |
43 | |
44 | |
45 | Statement::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 | |
56 | Statement::~Statement() |
57 | { |
58 | } |
59 | |
60 | |
61 | Statement& Statement::operator = (const Statement& stmt) |
62 | { |
63 | Statement tmp(stmt); |
64 | swap(tmp); |
65 | return *this; |
66 | } |
67 | |
68 | |
69 | void 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 | |
82 | Statement& Statement::reset(Session& rSession) |
83 | { |
84 | Statement stmt(rSession.createStatementImpl()); |
85 | swap(stmt); |
86 | return *this; |
87 | } |
88 | |
89 | |
90 | std::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 | |
117 | const 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 | |
127 | const 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 | |
137 | void Statement::setAsync(bool async) |
138 | { |
139 | _async = async; |
140 | if (_async && !_pAsyncExec) |
141 | _pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute); |
142 | } |
143 | |
144 | |
145 | std::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 | |
163 | const 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 | |
181 | Statement& Statement::operator , (Manipulator manip) |
182 | { |
183 | manip(*this); |
184 | return *this; |
185 | } |
186 | |
187 | |
188 | Statement& 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 | |
207 | Statement& Statement::(AbstractExtraction::Ptr ) |
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 | |
229 | Statement& 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 | |
239 | Statement& 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 | |
250 | Statement& 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 | |
270 | Statement& 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 | |
289 | Session Statement::session() |
290 | { |
291 | Poco::AutoPtr<SessionImpl> ps(&impl()->session(), true); |
292 | return Session(ps); |
293 | } |
294 | |
295 | |
296 | void 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 | |