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 | |
26 | namespace Poco { |
27 | namespace SQL { |
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 | { |
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 | |
57 | Statement::Statement(Statement&& stmt) |
58 | { |
59 | this->move(std::move(stmt)); |
60 | } |
61 | |
62 | |
63 | Statement::~Statement() |
64 | { |
65 | } |
66 | |
67 | |
68 | Statement& 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 | |
80 | void 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 | |
95 | Statement& Statement::operator = (Statement&& stmt) |
96 | { |
97 | this->move(std::move(stmt)); |
98 | return *this; |
99 | } |
100 | |
101 | |
102 | void 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 | |
114 | Statement& Statement::reset(Session& rSession) |
115 | { |
116 | Statement stmt(rSession.createStatementImpl()); |
117 | swap(stmt); |
118 | return *this; |
119 | } |
120 | |
121 | |
122 | std::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 | |
149 | const 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 | |
159 | const 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 | |
169 | void Statement::setAsync(bool async) |
170 | { |
171 | _async = async; |
172 | if (_async && !_pAsyncExec) |
173 | _pAsyncExec = new AsyncExecMethod(_pImpl, &StatementImpl::execute); |
174 | } |
175 | |
176 | |
177 | std::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 | |
195 | const 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 | |
213 | Statement& Statement::operator , (Manipulator manip) |
214 | { |
215 | manip(*this); |
216 | return *this; |
217 | } |
218 | |
219 | |
220 | Statement& 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 | |
239 | Statement& Statement::(AbstractExtraction::Ptr ) |
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 | |
261 | Statement& 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 | |
271 | Statement& 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 | |
282 | Statement& 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 | |
302 | Statement& 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 | |
321 | Session Statement::session() |
322 | { |
323 | Poco::AutoPtr<SessionImpl> ps(&impl()->session(), true); |
324 | return Session(ps); |
325 | } |
326 | |
327 | |
328 | void 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 | |