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