1//
2// RecordSet.cpp
3//
4// Library: SQL
5// Package: SQLCore
6// Module: RecordSet
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/RecordSet.h"
16#include "Poco/SQL/Date.h"
17#include "Poco/SQL/Time.h"
18#include "Poco/SQL/SQLException.h"
19#include "Poco/DateTime.h"
20#include "Poco/UTFString.h"
21
22
23using namespace Poco::SQL::Keywords;
24using Poco::DateTime;
25using Poco::UTF16String;
26
27
28namespace Poco {
29namespace SQL {
30
31
32RecordSet::RecordSet(const Statement& rStatement,
33 RowFormatter::Ptr pRowFormatter):
34 Statement(rStatement),
35 _currentRow(0),
36 _pBegin(new RowIterator(this, 0 == rowsExtracted())),
37 _pEnd(new RowIterator(this, true))
38{
39 if (pRowFormatter) setRowFormatter(pRowFormatter);
40}
41
42
43RecordSet::RecordSet(Session& rSession,
44 const std::string& query,
45 RowFormatter::Ptr pRowFormatter):
46 Statement((rSession << query, now)),
47 _currentRow(0),
48 _pBegin(new RowIterator(this, 0 == rowsExtracted())),
49 _pEnd(new RowIterator(this, true))
50{
51 if (pRowFormatter) setRowFormatter(pRowFormatter);
52}
53
54
55RecordSet::RecordSet(const RecordSet& other): Statement(other),
56 _currentRow(other._currentRow),
57 _pBegin(new RowIterator(this, 0 == rowsExtracted())),
58 _pEnd(new RowIterator(this, true)),
59 _pFilter(other._pFilter)
60{
61}
62
63
64RecordSet::RecordSet(RecordSet&& other): Statement(std::move(other))
65{
66 _currentRow = other._currentRow; other._currentRow = 0;
67 _pBegin = other._pBegin; other._pBegin = nullptr;
68 _pEnd = other._pEnd; other._pEnd = nullptr;
69 _pFilter = other._pFilter; other._pFilter = nullptr;
70 _rowMap = std::move(other._rowMap); other._rowMap.clear();
71}
72
73
74RecordSet::~RecordSet()
75{
76 try
77 {
78 delete _pBegin;
79 delete _pEnd;
80
81 RowMap::iterator it = _rowMap.begin();
82 RowMap::iterator itEnd = _rowMap.end();
83 for (; it != itEnd; ++it) delete it->second;
84 }
85 catch (...)
86 {
87 poco_unexpected();
88 }
89}
90
91
92RecordSet& RecordSet::reset(const Statement& stmt)
93{
94 delete _pBegin;
95 _pBegin = 0;
96 delete _pEnd;
97 _pEnd = 0;
98 _currentRow = 0;
99 Statement::setTotalRowCount(StatementImpl::UNKNOWN_TOTAL_ROW_COUNT);
100
101 RowMap::iterator it = _rowMap.begin();
102 RowMap::iterator end = _rowMap.end();
103 for (; it != end; ++it) delete it->second;
104 _rowMap.clear();
105
106 Statement::operator = (stmt);
107
108 _pBegin = new RowIterator(this, 0 == rowsExtracted());
109 _pEnd = new RowIterator(this, true);
110
111 return *this;
112}
113
114
115Poco::Dynamic::Var RecordSet::value(std::size_t col, std::size_t dataRow, bool useFilter) const
116{
117 if (useFilter && isFiltered() && !isAllowed(dataRow))
118 throw InvalidAccessException("Row not allowed");
119
120 if (isNull(col, dataRow)) return Poco::Dynamic::Var();
121
122 switch (columnType(col))
123 {
124 case MetaColumn::FDT_BOOL: return value<bool>(col, dataRow, useFilter);
125 case MetaColumn::FDT_INT8: return value<Int8>(col, dataRow, useFilter);
126 case MetaColumn::FDT_UINT8: return value<UInt8>(col, dataRow, useFilter);
127 case MetaColumn::FDT_INT16: return value<Int16>(col, dataRow, useFilter);
128 case MetaColumn::FDT_UINT16: return value<UInt16>(col, dataRow, useFilter);
129 case MetaColumn::FDT_INT32: return value<Int32>(col, dataRow, useFilter);
130 case MetaColumn::FDT_UINT32: return value<UInt32>(col, dataRow, useFilter);
131 case MetaColumn::FDT_INT64: return value<Int64>(col, dataRow, useFilter);
132 case MetaColumn::FDT_UINT64: return value<UInt64>(col, dataRow, useFilter);
133 case MetaColumn::FDT_FLOAT: return value<float>(col, dataRow, useFilter);
134 case MetaColumn::FDT_DOUBLE: return value<double>(col, dataRow, useFilter);
135 case MetaColumn::FDT_STRING: return value<std::string>(col, dataRow, useFilter);
136 case MetaColumn::FDT_WSTRING: return value<UTF16String>(col, dataRow, useFilter);
137 case MetaColumn::FDT_BLOB: return value<BLOB>(col, dataRow, useFilter);
138 case MetaColumn::FDT_CLOB: return value<CLOB>(col, dataRow, useFilter);
139 case MetaColumn::FDT_DATE: return value<Date>(col, dataRow, useFilter);
140 case MetaColumn::FDT_TIME: return value<Time>(col, dataRow, useFilter);
141 case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(col, dataRow);
142 default:
143 throw UnknownTypeException("Data type not supported.");
144 }
145}
146
147
148Poco::Dynamic::Var RecordSet::value(const std::string& name, std::size_t dataRow, bool useFilter) const
149{
150 if (useFilter && isFiltered() && !isAllowed(dataRow))
151 throw InvalidAccessException("Row not allowed");
152
153 if (isNull(metaColumn(name).position(), dataRow)) return Poco::Dynamic::Var();
154
155 switch (columnType(name))
156 {
157 case MetaColumn::FDT_BOOL: return value<bool>(name, dataRow, useFilter);
158 case MetaColumn::FDT_INT8: return value<Int8>(name, dataRow, useFilter);
159 case MetaColumn::FDT_UINT8: return value<UInt8>(name, dataRow, useFilter);
160 case MetaColumn::FDT_INT16: return value<Int16>(name, dataRow, useFilter);
161 case MetaColumn::FDT_UINT16: return value<UInt16>(name, dataRow, useFilter);
162 case MetaColumn::FDT_INT32: return value<Int32>(name, dataRow, useFilter);
163 case MetaColumn::FDT_UINT32: return value<UInt32>(name, dataRow, useFilter);
164 case MetaColumn::FDT_INT64: return value<Int64>(name, dataRow, useFilter);
165 case MetaColumn::FDT_UINT64: return value<UInt64>(name, dataRow, useFilter);
166 case MetaColumn::FDT_FLOAT: return value<float>(name, dataRow, useFilter);
167 case MetaColumn::FDT_DOUBLE: return value<double>(name, dataRow, useFilter);
168 case MetaColumn::FDT_STRING: return value<std::string>(name, dataRow, useFilter);
169 case MetaColumn::FDT_WSTRING: return value<UTF16String>(name, dataRow, useFilter);
170 case MetaColumn::FDT_BLOB: return value<BLOB>(name, dataRow, useFilter);
171 case MetaColumn::FDT_DATE: return value<Date>(name, dataRow, useFilter);
172 case MetaColumn::FDT_TIME: return value<Time>(name, dataRow, useFilter);
173 case MetaColumn::FDT_TIMESTAMP: return value<DateTime>(name, dataRow, useFilter);
174 default:
175 throw UnknownTypeException("Data type not supported.");
176 }
177}
178
179
180Row& RecordSet::row(std::size_t pos)
181{
182 std::size_t rowCnt = rowCount();
183 if (0 == rowCnt || pos > rowCnt - 1)
184 throw RangeException("Invalid recordset row requested.");
185
186 RowMap::const_iterator it = _rowMap.find(pos);
187 Row* pRow = 0;
188 std::size_t columns = columnCount();
189 if (it == _rowMap.end())
190 {
191 if (_rowMap.size())
192 {
193 //reuse first row column names and sorting fields to save some memory
194 pRow = new Row(_rowMap.begin()->second->names(),
195 _rowMap.begin()->second->getSortMap(),
196 getRowFormatter());
197
198 for (std::size_t col = 0; col < columns; ++col)
199 pRow->set(col, value(col, pos));
200 }
201 else
202 {
203 pRow = new Row;
204 pRow->setFormatter(getRowFormatter());
205 for (std::size_t col = 0; col < columns; ++col)
206 pRow->append(metaColumn(static_cast<UInt32>(col)).name(), value(col, pos));
207 }
208
209 _rowMap.insert(RowMap::value_type(pos, pRow));
210 }
211 else
212 {
213 pRow = it->second;
214 poco_check_ptr (pRow);
215 }
216
217 return *pRow;
218}
219
220
221std::size_t RecordSet::rowCount() const
222{
223 if (0 == extractions().size() && 0 == columnsExtracted())
224 return 0;
225 poco_assert (extractions().size());
226 std::size_t rc = storageRowCount();
227 if (!isFiltered()) return rc;
228
229 std::size_t counter = 0;
230 for (int dataRow = 0; dataRow < rc; ++dataRow)
231 {
232 if (isAllowed(dataRow)) ++counter;
233 }
234
235 return counter;
236}
237
238
239bool RecordSet::isAllowed(std::size_t dataRow) const
240{
241 if (!isFiltered()) return true;
242 return _pFilter->isAllowed(dataRow);
243}
244
245
246bool RecordSet::moveFirst()
247{
248 const size_t rc = storageRowCount();
249 if (rc > 0)
250 {
251 if (!isFiltered())
252 {
253 _currentRow = 0;
254 return true;
255 }
256
257 std::size_t currentRow = 0;
258 while (!isAllowed(currentRow))
259 {
260 if (currentRow >= rc - 1) return false;
261 ++currentRow;
262 }
263
264 _currentRow = currentRow;
265 return true;
266 }
267 else return false;
268}
269
270
271bool RecordSet::moveNext()
272{
273 std::size_t currentRow = _currentRow;
274 do
275 {
276 if (currentRow >= storageRowCount() -1) return false;
277 ++currentRow;
278 } while (isFiltered() && !isAllowed(currentRow));
279
280 _currentRow = currentRow;
281 return true;
282}
283
284
285bool RecordSet::movePrevious()
286{
287 std::size_t currentRow = _currentRow;
288 do
289 {
290 if (currentRow <= 0) return false;
291 --currentRow;
292 } while (isFiltered() && !isAllowed(currentRow));
293
294 _currentRow = currentRow;
295 return true;
296}
297
298
299bool RecordSet::moveLast()
300{
301 if (storageRowCount() > 0)
302 {
303 std::size_t currentRow = subTotalRowCount() - 1;
304 if (!isFiltered())
305 {
306 _currentRow = currentRow;
307 return true;
308 }
309
310 while (!isAllowed(currentRow))
311 {
312 if (currentRow <= 0) return false;
313 --currentRow;
314 }
315
316 _currentRow = currentRow;
317 return true;
318 }
319 else return false;
320}
321
322
323void RecordSet::setRowFormatter(RowFormatter::Ptr pRowFormatter)
324{
325 if (pRowFormatter)
326 {
327 if (pRowFormatter->getTotalRowCount() == RowFormatter::INVALID_ROW_COUNT)
328 pRowFormatter->setTotalRowCount(static_cast<int>(getTotalRowCount()));
329
330 Statement::setRowFormatter(pRowFormatter);
331 RowMap::iterator it = _rowMap.begin();
332 RowMap::iterator itEnd = _rowMap.end();
333 for (; it != itEnd; ++it) it->second->setFormatter(getRowFormatter());
334 }
335 else
336 throw NullPointerException("Null RowFormatter in RecordSet.");
337}
338
339
340std::ostream& RecordSet::copyNames(std::ostream& os) const
341{
342 if (begin() == end()) return os;
343
344 std::string names = (*_pBegin)->namesToString();
345 if (!names.empty()) os << names;
346 return os;
347}
348
349
350std::ostream& RecordSet::copyValues(std::ostream& os, std::size_t offset, std::size_t length) const
351{
352 if (begin() == end()) return os;
353
354 RowIterator it = *_pBegin + offset;
355 RowIterator itEnd = (RowIterator::POSITION_END != length) ? it + length : *_pEnd;
356 std::copy(it, itEnd, std::ostream_iterator<Row>(os));
357 return os;
358}
359
360
361void RecordSet::formatValues(std::size_t offset, std::size_t length) const
362{
363 if (begin() == end()) return;
364
365 RowIterator it = *_pBegin + offset;
366 RowIterator itEnd = (RowIterator::POSITION_END != length) ? it + length : *_pEnd;
367 std::string val;
368 for (; it != itEnd; ++it) it->formatValues();
369}
370
371
372std::ostream& RecordSet::copy(std::ostream& os, std::size_t offset, std::size_t length) const
373{
374 if (begin() == end()) return os;
375
376 RowFormatter& rf = const_cast<RowFormatter&>((*_pBegin)->getFormatter());
377 rf.setTotalRowCount(static_cast<int>(getTotalRowCount()));
378 if (RowFormatter::FORMAT_PROGRESSIVE == rf.getMode())
379 {
380 os << rf.prefix();
381 copyNames(os);
382 copyValues(os, offset, length);
383 os << rf.postfix();
384 }
385 else
386 {
387 formatNames();
388 formatValues(offset, length);
389 os << rf.toString();
390 }
391
392 return os;
393}
394
395
396void RecordSet::filter(const Poco::AutoPtr<RowFilter>& pFilter)
397{
398 _pFilter = pFilter;
399}
400
401
402bool RecordSet::isFiltered() const
403{
404 return _pFilter && !_pFilter->isEmpty();
405}
406
407
408} } // namespace Poco::SQL
409