1//
2// SQLiteStatementImpl.cpp
3//
4// Library: SQL/SQLite
5// Package: SQLite
6// Module: SQLiteStatementImpl
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/SQLite/SQLiteStatementImpl.h"
16#include "Poco/SQL/SQLite/Utility.h"
17#include "Poco/SQL/SQLite/SQLiteException.h"
18#include "Poco/String.h"
19#include <cstdlib>
20#include <cstring>
21#if defined(POCO_UNBUNDLED)
22#include <sqlite3.h>
23#else
24#include "sqlite3.h"
25#endif
26
27
28namespace Poco {
29namespace SQL {
30namespace SQLite {
31
32
33const int SQLiteStatementImpl::POCO_SQLITE_INV_ROW_CNT = -1;
34
35
36SQLiteStatementImpl::SQLiteStatementImpl(Poco::SQL::SessionImpl& rSession, sqlite3* pDB):
37 StatementImpl(rSession),
38 _pDB(pDB),
39 _pStmt(0),
40 _stepCalled(false),
41 _nextResponse(0),
42 _affectedRowCount(POCO_SQLITE_INV_ROW_CNT),
43 _canBind(false),
44 _isExtracted(false),
45 _canCompile(true)
46{
47 _columns.resize(1);
48}
49
50
51SQLiteStatementImpl::~SQLiteStatementImpl()
52{
53 try
54 {
55 clear();
56 }
57 catch (...)
58 {
59 poco_unexpected();
60 }
61}
62
63
64void SQLiteStatementImpl::compileImpl()
65{
66 if (!_pLeftover)
67 {
68 _bindBegin = bindings().begin();
69 }
70
71 std::string statement(toString());
72
73 sqlite3_stmt* pStmt = 0;
74 const char* pSql = _pLeftover ? _pLeftover->c_str() : statement.c_str();
75
76 if (0 == std::strlen(pSql))
77 throw InvalidSQLStatementException("Empty statements are illegal");
78
79 int rc = SQLITE_OK;
80 const char* pLeftover = 0;
81 bool queryFound = false;
82
83 do
84 {
85 rc = sqlite3_prepare_v2(_pDB, pSql, -1, &pStmt, &pLeftover);
86 if (rc != SQLITE_OK)
87 {
88 if (pStmt) sqlite3_finalize(pStmt);
89 pStmt = 0;
90 std::string errMsg = sqlite3_errmsg(_pDB);
91 Utility::throwException(_pDB, rc, errMsg);
92 }
93 else if (rc == SQLITE_OK && pStmt)
94 {
95 queryFound = true;
96 }
97 else if (rc == SQLITE_OK && !pStmt) // comment/whitespace ignore
98 {
99 pSql = pLeftover;
100 if (std::strlen(pSql) == 0)
101 {
102 // empty statement or an conditional statement! like CREATE IF NOT EXISTS
103 // this is valid
104 queryFound = true;
105 }
106 }
107 } while (rc == SQLITE_OK && !pStmt && !queryFound);
108
109 //Finalization call in clear() invalidates the pointer, so the value is remembered here.
110 //For last statement in a batch (or a single statement), pLeftover == "", so the next call
111 // to compileImpl() shall return false immediately when there are no more statements left.
112 std::string leftOver(pLeftover);
113 trimInPlace(leftOver);
114 clear();
115 _pStmt = pStmt;
116 if (!leftOver.empty())
117 {
118 _pLeftover = new std::string(leftOver);
119 _canCompile = true;
120 }
121 else _canCompile = false;
122
123 _pBinder = new Binder(_pStmt);
124 _pExtractor = new Extractor(_pStmt);
125
126 if (SQLITE_DONE == _nextResponse && _isExtracted)
127 {
128 //if this is not the first compile and there has already been extraction
129 //during previous step, switch to the next set if there is one provided
130 if (hasMoreDataSets())
131 {
132 activateNextDataSet();
133 _isExtracted = false;
134 }
135 }
136
137 int colCount = sqlite3_column_count(_pStmt);
138
139 if (colCount)
140 {
141 std::size_t curDataSet = currentDataSet();
142 if (curDataSet >= _columns.size()) _columns.resize(curDataSet + 1);
143 for (int i = 0; i < colCount; ++i)
144 {
145 MetaColumn mc(i, sqlite3_column_name(_pStmt, i), Utility::getColumnType(_pStmt, i));
146 _columns[curDataSet].push_back(mc);
147 }
148 }
149}
150
151
152void SQLiteStatementImpl::bindImpl()
153{
154 _stepCalled = false;
155 _nextResponse = 0;
156 if (_pStmt == 0) return;
157
158 sqlite3_reset(_pStmt);
159
160 int paramCount = sqlite3_bind_parameter_count(_pStmt);
161 if (0 == paramCount)
162 {
163 _canBind = false;
164 return;
165 }
166
167 BindIt bindEnd = bindings().end();
168 std::size_t availableCount = 0;
169 Bindings::difference_type bindCount = 0;
170 Bindings::iterator it = _bindBegin;
171 for (; it != bindEnd; ++it)
172 {
173 availableCount += (*it)->numOfColumnsHandled();
174 if (availableCount <= paramCount) ++bindCount;
175 else break;
176 }
177
178 if (availableCount < paramCount)
179 throw ParameterCountMismatchException();
180
181 Bindings::difference_type remainingBindCount = bindEnd - _bindBegin;
182 if (bindCount < remainingBindCount)
183 {
184 bindEnd = _bindBegin + bindCount;
185 _canBind = true;
186 }
187 else if (bindCount > remainingBindCount)
188 throw ParameterCountMismatchException();
189
190 std::size_t boundRowCount;
191 if (_bindBegin != bindings().end())
192 {
193 boundRowCount = (*_bindBegin)->numOfRowsHandled();
194
195 Bindings::iterator oldBegin = _bindBegin;
196 for (std::size_t pos = 1; _bindBegin != bindEnd && (*_bindBegin)->canBind(); ++_bindBegin)
197 {
198 if (boundRowCount != (*_bindBegin)->numOfRowsHandled())
199 throw BindingException("Size mismatch in Bindings. All Bindings MUST have the same size");
200
201 std::size_t namedBindPos = 0;
202 if (!(*_bindBegin)->name().empty())
203 namedBindPos = (std::size_t)sqlite3_bind_parameter_index(_pStmt, (*_bindBegin)->name().c_str());
204
205 (*_bindBegin)->bind((namedBindPos != 0) ? namedBindPos : pos);
206 pos += (*_bindBegin)->numOfColumnsHandled();
207 }
208
209 if ((*oldBegin)->canBind())
210 {
211 //container binding will come back for more, so we must rewind
212 _bindBegin = oldBegin;
213 _canBind = true;
214 }
215 else _canBind = false;
216 }
217}
218
219
220void SQLiteStatementImpl::clear()
221{
222 _columns[currentDataSet()].clear();
223 _affectedRowCount = POCO_SQLITE_INV_ROW_CNT;
224
225 if (_pStmt)
226 {
227 sqlite3_finalize(_pStmt);
228 _pStmt=0;
229 }
230 _pLeftover = 0;
231}
232
233
234bool SQLiteStatementImpl::hasNext()
235{
236 if (_stepCalled)
237 return (_nextResponse == SQLITE_ROW);
238
239 // _pStmt is allowed to be null for conditional SQL statements
240 if (_pStmt == 0)
241 {
242 _stepCalled = true;
243 _nextResponse = SQLITE_DONE;
244 return false;
245 }
246
247 _stepCalled = true;
248 _nextResponse = sqlite3_step(_pStmt);
249
250 if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0;
251 if (!sqlite3_stmt_readonly(_pStmt))
252 _affectedRowCount += sqlite3_changes(_pDB);
253
254 if (_nextResponse != SQLITE_ROW && _nextResponse != SQLITE_OK && _nextResponse != SQLITE_DONE)
255 Utility::throwException(_pDB, _nextResponse);
256
257 _pExtractor->reset();//clear the cached null indicators
258
259 return (_nextResponse == SQLITE_ROW);
260}
261
262
263std::size_t SQLiteStatementImpl::next()
264{
265 if (SQLITE_ROW == _nextResponse)
266 {
267 poco_assert (columnsReturned() == sqlite3_column_count(_pStmt));
268
269 Extractions& extracts = extractions();
270 Extractions::iterator it = extracts.begin();
271 Extractions::iterator itEnd = extracts.end();
272 std::size_t pos = 0; // sqlite starts with pos 0 for results!
273 for (; it != itEnd; ++it)
274 {
275 (*it)->extract(pos);
276 pos += (*it)->numOfColumnsHandled();
277 _isExtracted = true;
278 }
279 _stepCalled = false;
280 if (_affectedRowCount == POCO_SQLITE_INV_ROW_CNT) _affectedRowCount = 0;
281
282 if (extracts.size())
283 _affectedRowCount += static_cast<int>((*extracts.begin())->numOfRowsHandled());
284 else
285 {
286 _affectedRowCount += static_cast<int>((*extracts.begin())->numOfRowsHandled());
287 }
288 }
289 else if (SQLITE_DONE == _nextResponse)
290 {
291 throw Poco::SQL::SQLException("No data received");
292 }
293 else
294 {
295 Utility::throwException(_pDB, _nextResponse, std::string("Iterator Error: trying to access the next value"));
296 }
297
298 return 1u;
299}
300
301
302std::size_t SQLiteStatementImpl::columnsReturned() const
303{
304 return (std::size_t) _columns[currentDataSet()].size();
305}
306
307
308const MetaColumn& SQLiteStatementImpl::metaColumn(std::size_t pos, std::size_t dataSet) const
309{
310 poco_assert (pos >= 0 && pos <= _columns[dataSet].size());
311 return _columns[dataSet][pos];
312}
313
314
315int SQLiteStatementImpl::affectedRowCount() const
316{
317 if (_affectedRowCount != POCO_SQLITE_INV_ROW_CNT) return _affectedRowCount;
318 return _pStmt == 0 || sqlite3_stmt_readonly(_pStmt) ? 0 : sqlite3_changes(_pDB);
319}
320
321
322} } } // namespace Poco::SQL::SQLite
323