mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 08:31:43 +02:00
proper bool support
This commit is contained in:
@@ -280,7 +280,7 @@ inline void Binder::bind(std::size_t pos, const double& val, Direction dir)
|
||||
|
||||
inline void Binder::bind(std::size_t pos, const bool& val, Direction dir)
|
||||
{
|
||||
bindImpl(pos, val, Utility::boolDataType, dir);
|
||||
bindImpl(pos, val, SQL_C_BIT, dir);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -295,7 +295,7 @@ inline void Preparation::prepare(std::size_t pos, Poco::UInt64)
|
||||
|
||||
inline void Preparation::prepare(std::size_t pos, bool)
|
||||
{
|
||||
preparePOD<bool>(pos, Utility::boolDataType);
|
||||
preparePOD<bool>(pos, SQL_C_BIT);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -101,9 +101,6 @@ public:
|
||||
static void dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt);
|
||||
/// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT.
|
||||
|
||||
static const SQLSMALLINT boolDataType;
|
||||
/// ODBC size for bool data type.
|
||||
|
||||
private:
|
||||
static const TypeInfo _dataTypes;
|
||||
/// C <==> SQL data type mapping
|
||||
|
@@ -224,7 +224,7 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
|
||||
case NULL_UINT32: bindNull(pos, SQL_C_ULONG); break;
|
||||
case NULL_INT64: bindNull(pos, SQL_C_SBIGINT); break;
|
||||
case NULL_UINT64: bindNull(pos, SQL_C_UBIGINT); break;
|
||||
case NULL_BOOL: bindNull(pos, Utility::boolDataType); break;
|
||||
case NULL_BOOL: bindNull(pos, SQL_C_BIT); break;
|
||||
case NULL_FLOAT: bindNull(pos, SQL_C_FLOAT); break;
|
||||
case NULL_DOUBLE: bindNull(pos, SQL_C_DOUBLE); break;
|
||||
case NULL_STRING: bindNull(pos, SQL_C_CHAR); break;
|
||||
|
@@ -358,7 +358,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
|
||||
bool Extractor::extract(std::size_t pos, bool& val)
|
||||
{
|
||||
if (Preparation::DE_MANUAL == _dataExtraction)
|
||||
return extractManualImpl(pos, val, Utility::boolDataType);
|
||||
return extractManualImpl(pos, val, SQL_C_BIT);
|
||||
else
|
||||
return extractBoundImpl(pos, val);
|
||||
}
|
||||
|
@@ -101,6 +101,8 @@ void ODBCColumn::init()
|
||||
setNullable(SQL_NULLABLE == _columnDesc.isNullable);
|
||||
switch(_columnDesc.dataType)
|
||||
{
|
||||
case SQL_BIT:
|
||||
setType(MetaColumn::FDT_BOOL); break;
|
||||
case SQL_CHAR:
|
||||
case SQL_VARCHAR:
|
||||
case SQL_LONGVARCHAR:
|
||||
|
@@ -125,7 +125,7 @@ void Preparation::prepare(std::size_t pos, const Poco::Any&)
|
||||
return preparePOD<Poco::UInt64>(pos, SQL_C_UBIGINT);
|
||||
|
||||
case MetaColumn::FDT_BOOL:
|
||||
return preparePOD<bool>(pos, Utility::boolDataType);
|
||||
return preparePOD<bool>(pos, SQL_C_BIT);
|
||||
|
||||
case MetaColumn::FDT_FLOAT:
|
||||
return preparePOD<float>(pos, SQL_C_FLOAT);
|
||||
|
@@ -48,8 +48,6 @@ namespace ODBC {
|
||||
|
||||
|
||||
const TypeInfo Utility::_dataTypes;
|
||||
const SQLSMALLINT Utility::boolDataType = (sizeof(bool) <= sizeof(char)) ? SQL_C_TINYINT :
|
||||
(sizeof(bool) == sizeof(short)) ? SQL_C_SHORT : SQL_C_LONG;
|
||||
|
||||
|
||||
Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap)
|
||||
|
@@ -972,6 +972,28 @@ void ODBCPostgreSQLTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::testStdVectorBool()
|
||||
{
|
||||
|
||||
// psqlODBC driver returns string for bool fields
|
||||
// even when field is explicitly cast to boolean,
|
||||
// so this functionality seems to be untestable with it
|
||||
|
||||
#ifdef POCO_ODBC_USE_MAMMOTH_NG
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateBoolTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->stdVectorBool();
|
||||
i += 2;
|
||||
}
|
||||
#endif // POCO_ODBC_USE_MAMMOTH_NG
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::configurePLPgSQL()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@@ -1110,6 +1132,15 @@ void ODBCPostgreSQLTest::recreateNullsTable(const std::string& notNull)
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::recreateBoolTable()
|
||||
{
|
||||
dropObject("TABLE", "BoolTest");
|
||||
try { *_pSession << "CREATE TABLE BoolTest (b BOOLEAN)", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateBoolTable()"); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateBoolTable()"); }
|
||||
}
|
||||
|
||||
|
||||
bool ODBCPostgreSQLTest::canConnect(const std::string& driver, const std::string& dsn)
|
||||
{
|
||||
Utility::DriverMap::iterator itDrv = _drivers.begin();
|
||||
@@ -1285,6 +1316,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStdVectorBool);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@
|
||||
|
||||
|
||||
// uncomment to use Mammoth ODBCng driver
|
||||
//#define POCO_ODBC_USE_MAMMOTH_NG
|
||||
#define POCO_ODBC_USE_MAMMOTH_NG
|
||||
|
||||
|
||||
class ODBCPostgreSQLTest: public CppUnit::TestCase
|
||||
@@ -131,6 +131,7 @@ public:
|
||||
void testStoredFunction();
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
void testStdVectorBool();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
@@ -152,6 +153,7 @@ private:
|
||||
void recreateTuplesTable();
|
||||
void recreateVectorsTable();
|
||||
void recreateNullsTable(const std::string& notNull="");
|
||||
void recreateBoolTable();
|
||||
|
||||
static bool init(const std::string& driver, const std::string& dsn);
|
||||
static bool canConnect(const std::string& driver, const std::string& dsn);
|
||||
|
@@ -1070,6 +1070,21 @@ void ODBCSQLServerTest::testRowIterator()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::testStdVectorBool()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
recreateBoolTable();
|
||||
_pSession->setFeature("autoBind", bindValues[i]);
|
||||
_pSession->setFeature("autoExtract", bindValues[i+1]);
|
||||
_pExecutor->stdVectorBool();
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@@ -1190,6 +1205,14 @@ void ODBCSQLServerTest::recreateNullsTable(const std::string& notNull)
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateNullsTable()"); }
|
||||
}
|
||||
|
||||
void ODBCSQLServerTest::recreateBoolTable()
|
||||
{
|
||||
dropObject("TABLE", "BoolTest");
|
||||
try { *_pSession << "CREATE TABLE BoolTest (b BIT)", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateBoolTable()"); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateBoolTable()"); }
|
||||
}
|
||||
|
||||
|
||||
bool ODBCSQLServerTest::canConnect(const std::string& driver, const std::string& dsn)
|
||||
{
|
||||
@@ -1338,6 +1361,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInternalStorageType);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStdVectorBool);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@@ -127,6 +127,7 @@ public:
|
||||
|
||||
void testNull();
|
||||
void testRowIterator();
|
||||
void testStdVectorBool();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
@@ -149,6 +150,7 @@ private:
|
||||
void recreateVectorTable();
|
||||
void recreateVectorsTable();
|
||||
void recreateNullsTable(const std::string& notNull = "");
|
||||
void recreateBoolTable();
|
||||
|
||||
static bool init(const std::string& driver, const std::string& dsn);
|
||||
static bool canConnect(const std::string& driver, const std::string& dsn);
|
||||
|
@@ -2152,7 +2152,7 @@ void SQLExecutor::nulls()
|
||||
|
||||
void SQLExecutor::rowIterator()
|
||||
{
|
||||
std::string funct = "internalExtraction()";
|
||||
std::string funct = "rowIterator()";
|
||||
std::vector<Tuple<int, double, std::string> > v;
|
||||
v.push_back(Tuple<int, double, std::string>(1, 1.5f, "3"));
|
||||
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4"));
|
||||
@@ -2179,3 +2179,63 @@ void SQLExecutor::rowIterator()
|
||||
std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
|
||||
assert (osLoop.str() == osCopy.str());
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::stdVectorBool()
|
||||
{
|
||||
std::string funct = "stdVectorBool()";
|
||||
|
||||
bool b = false;
|
||||
try { *_pSession << "INSERT INTO BoolTest VALUES (?)", use(b), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
b = true;
|
||||
*_pSession << "SELECT * FROM BoolTest", into(b), now;
|
||||
assert (false == b);
|
||||
*_pSession << "DELETE FROM BoolTest", now;
|
||||
|
||||
b = true;
|
||||
try { *_pSession << "INSERT INTO BoolTest VALUES (?)", use(b), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
b = false;
|
||||
*_pSession << "SELECT * FROM BoolTest", into(b), now;
|
||||
assert (true == b);
|
||||
*_pSession << "DELETE FROM BoolTest", now;
|
||||
|
||||
std::vector<bool> v;
|
||||
v.push_back(true);
|
||||
v.push_back(false);
|
||||
v.push_back(false);
|
||||
v.push_back(true);
|
||||
|
||||
try { *_pSession << "INSERT INTO BoolTest VALUES (?)", use(v), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
v.clear();
|
||||
*_pSession << "SELECT * FROM BoolTest", into(v), now;
|
||||
|
||||
assert (4 == v.size());
|
||||
std::vector<bool>::iterator it = v.begin();
|
||||
std::vector<bool>::iterator end = v.end();
|
||||
int t = 0;
|
||||
for (; it != end; ++it)
|
||||
t += *it ? 1 : 0;
|
||||
assert (2 == t);
|
||||
|
||||
try { *_pSession << "SELECT * FROM BoolTest WHERE b = ?", out(v), now; fail("must fail"); }
|
||||
catch (BindingException&) { }
|
||||
|
||||
try { *_pSession << "SELECT * FROM BoolTest WHERE b = ?", io(v), now; fail("must fail"); }
|
||||
catch (BindingException&) { }
|
||||
|
||||
RecordSet rset(*_pSession, "SELECT * FROM BoolTest");
|
||||
|
||||
t = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
t += rset.value<bool>(0, i) ? 1 : 0;
|
||||
assert (2 == t);
|
||||
}
|
||||
|
@@ -132,6 +132,7 @@ public:
|
||||
void nulls();
|
||||
void notNulls(const std::string& sqlState = "23502");
|
||||
void rowIterator();
|
||||
void stdVectorBool();
|
||||
|
||||
private:
|
||||
Poco::Data::Session* _pSession;
|
||||
|
@@ -164,6 +164,79 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class Binding<std::vector<bool> >: public AbstractBinding
|
||||
/// Specialization for std::vector<bool>.
|
||||
/// This specialization is necessary due to the nature of std::vector<bool>.
|
||||
/// For details, see the standard library implementation of std::vector<bool>
|
||||
/// or
|
||||
/// S. Meyers: "Effective STL" (Copyright Addison-Wesley 2001),
|
||||
/// Item 18: "Avoid using vector<bool>."
|
||||
///
|
||||
/// The workaround employed here is using std::deque<bool> as an
|
||||
/// internal replacement container.
|
||||
///
|
||||
/// IMPORTANT:
|
||||
/// Only IN binding is supported.
|
||||
{
|
||||
public:
|
||||
explicit Binding(const std::vector<bool>& val, const std::string& name = "", Direction direction = PD_IN):
|
||||
AbstractBinding(name, direction),
|
||||
_val(val),
|
||||
_deq(_val.begin(), _val.end()),
|
||||
_begin(_deq.begin()),
|
||||
_end(_deq.end())
|
||||
/// Creates the Binding.
|
||||
{
|
||||
if (PD_IN != direction)
|
||||
throw BindingException("Only IN direction is legal for std:vector<bool> binding.");
|
||||
|
||||
if (numOfRowsHandled() == 0)
|
||||
throw BindingException("It is illegal to bind to an empty data collection");
|
||||
}
|
||||
|
||||
~Binding()
|
||||
/// Destroys the Binding.
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t numOfColumnsHandled() const
|
||||
{
|
||||
return TypeHandler<bool>::size();
|
||||
}
|
||||
|
||||
std::size_t numOfRowsHandled() const
|
||||
{
|
||||
return _val.size();
|
||||
}
|
||||
|
||||
bool canBind() const
|
||||
{
|
||||
return _begin != _end;
|
||||
}
|
||||
|
||||
void bind(std::size_t pos)
|
||||
{
|
||||
poco_assert_dbg(getBinder() != 0);
|
||||
poco_assert_dbg(canBind());
|
||||
TypeHandler<bool>::bind(pos, *_begin, getBinder(), getDirection());
|
||||
++_begin;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
_begin = _deq.begin();
|
||||
_end = _deq.end();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<bool>& _val;
|
||||
std::deque<bool> _deq;
|
||||
std::deque<bool>::const_iterator _begin;
|
||||
std::deque<bool>::const_iterator _end;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class Binding<std::list<T> >: public AbstractBinding
|
||||
/// Specialization for std::list.
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -184,6 +185,157 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
class Column<bool, std::vector<bool> >
|
||||
/// The std::vector<bool> specialization for the Column class.
|
||||
///
|
||||
/// This specialization is necessary due to the nature of std::vector<bool>.
|
||||
/// For details, see the standard library implementation of vector<bool>
|
||||
/// or
|
||||
/// S. Meyers: "Effective STL" (Copyright Addison-Wesley 2001),
|
||||
/// Item 18: "Avoid using vector<bool>."
|
||||
///
|
||||
/// The workaround employed here is using deque<bool> as an
|
||||
/// internal "companion" container kept in sync with the vector<bool>
|
||||
/// column data.
|
||||
{
|
||||
public:
|
||||
typedef std::vector<bool> Container;
|
||||
typedef Container::const_iterator Iterator;
|
||||
typedef Container::const_reverse_iterator RIterator;
|
||||
typedef Container::size_type Size;
|
||||
|
||||
Column(const MetaColumn& metaColumn, Container* pData):
|
||||
_metaColumn(metaColumn),
|
||||
_pData(pData)
|
||||
/// Creates the Column.
|
||||
{
|
||||
poco_check_ptr (_pData);
|
||||
_deque.assign(_pData->begin(), _pData->end());
|
||||
}
|
||||
|
||||
Column(const Column& col):
|
||||
_metaColumn(col._metaColumn),
|
||||
_pData(col._pData)
|
||||
/// Creates the Column.
|
||||
{
|
||||
_deque.assign(_pData->begin(), _pData->end());
|
||||
}
|
||||
|
||||
~Column()
|
||||
/// Destroys the Column.
|
||||
{
|
||||
}
|
||||
|
||||
Column& operator = (const Column& col)
|
||||
/// Assignment operator.
|
||||
{
|
||||
Column tmp(col);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(Column& other)
|
||||
/// Swaps the column with another one.
|
||||
{
|
||||
std::swap(_metaColumn, other._metaColumn);
|
||||
std::swap(_pData, other._pData);
|
||||
std::swap(_deque, other._deque);
|
||||
}
|
||||
|
||||
Container& data()
|
||||
/// Returns reference to contained data.
|
||||
{
|
||||
return *_pData;
|
||||
}
|
||||
|
||||
const bool& value(std::size_t row) const
|
||||
/// Returns the field value in specified row.
|
||||
{
|
||||
if (_deque.size() < _pData->size())
|
||||
_deque.resize(_pData->size());
|
||||
|
||||
try
|
||||
{
|
||||
return _deque.at(row) = _pData->at(row);
|
||||
}
|
||||
catch (std::out_of_range& ex)
|
||||
{
|
||||
throw RangeException(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
const bool& operator [] (std::size_t row) const
|
||||
/// Returns the field value in specified row.
|
||||
{
|
||||
return value(row);
|
||||
}
|
||||
|
||||
Size rowCount() const
|
||||
/// Returns number of rows.
|
||||
{
|
||||
return _pData->size();
|
||||
}
|
||||
|
||||
void reset()
|
||||
/// Clears and shrinks the storage.
|
||||
{
|
||||
Container().swap(*_pData);
|
||||
_deque.clear();
|
||||
}
|
||||
|
||||
const std::string& name() const
|
||||
/// Returns column name.
|
||||
{
|
||||
return _metaColumn.name();
|
||||
}
|
||||
|
||||
std::size_t length() const
|
||||
/// Returns column maximum length.
|
||||
{
|
||||
return _metaColumn.length();
|
||||
}
|
||||
|
||||
std::size_t precision() const
|
||||
/// Returns column precision.
|
||||
/// Valid for floating point fields only (zero for other data types).
|
||||
{
|
||||
return _metaColumn.precision();
|
||||
}
|
||||
|
||||
std::size_t position() const
|
||||
/// Returns column position.
|
||||
{
|
||||
return _metaColumn.position();
|
||||
}
|
||||
|
||||
MetaColumn::ColumnDataType type() const
|
||||
/// Returns column type.
|
||||
{
|
||||
return _metaColumn.type();
|
||||
}
|
||||
|
||||
Iterator begin() const
|
||||
/// Returns iterator pointing to the beginning of data storage vector.
|
||||
{
|
||||
return _pData->begin();
|
||||
}
|
||||
|
||||
Iterator end() const
|
||||
/// Returns iterator pointing to the end of data storage vector.
|
||||
{
|
||||
return _pData->end();
|
||||
}
|
||||
|
||||
private:
|
||||
Column();
|
||||
|
||||
MetaColumn _metaColumn;
|
||||
Poco::SharedPtr<Container> _pData;
|
||||
mutable std::deque<bool> _deque;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class Column<T, std::list<T> >
|
||||
/// Column specialization for std::list
|
||||
|
@@ -171,8 +171,13 @@ public:
|
||||
void extract(std::size_t pos)
|
||||
{
|
||||
AbstractExtractor* pExt = getExtractor();
|
||||
_rResult.push_back(_default);
|
||||
TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt);
|
||||
|
||||
// for vector specialization, a temporary must be used to
|
||||
// allow for extraction of bool values
|
||||
T tmp = _default;
|
||||
TypeHandler<T>::extract(pos, tmp, _default, pExt);
|
||||
_rResult.push_back(tmp);
|
||||
|
||||
_nulls.push_back(pExt->isNull(pos));
|
||||
}
|
||||
|
||||
|
@@ -180,25 +180,25 @@ public:
|
||||
/// Returns the data value at named column, row location.
|
||||
|
||||
template <typename C>
|
||||
DynamicAny nvl(const std::string& name, const C& deflt)
|
||||
const C& nvl(const std::string& name, const C& deflt) const
|
||||
/// Returns the value in the named column of the current row
|
||||
/// if the value is not NULL, or deflt otherwise.
|
||||
{
|
||||
if (isNull(name))
|
||||
return DynamicAny(deflt);
|
||||
return deflt;
|
||||
else
|
||||
return value(name);
|
||||
return value<C>(name, _currentRow);
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
DynamicAny nvl(std::size_t index, const C& deflt)
|
||||
const C& nvl(std::size_t index, const C& deflt) const
|
||||
/// Returns the value in the given column of the current row
|
||||
/// if the value is not NULL, or deflt otherwise.
|
||||
{
|
||||
if (isNull(index))
|
||||
return DynamicAny(deflt);
|
||||
return deflt;
|
||||
else
|
||||
return value(index);
|
||||
return value<C>(index, _currentRow);
|
||||
}
|
||||
|
||||
const RowIterator& begin();
|
||||
@@ -267,7 +267,7 @@ public:
|
||||
/// Returns column precision for the column with specified name.
|
||||
/// Valid for floating point fields only (zero for other data types).
|
||||
|
||||
bool isNull(const std::string& name);
|
||||
bool isNull(const std::string& name) const;
|
||||
/// Returns true if column value of the current row is null.
|
||||
|
||||
private:
|
||||
@@ -394,7 +394,7 @@ inline std::size_t RecordSet::columnPrecision(const std::string& name)const
|
||||
}
|
||||
|
||||
|
||||
inline bool RecordSet::isNull(const std::string& name)
|
||||
inline bool RecordSet::isNull(const std::string& name) const
|
||||
{
|
||||
return isNull(metaColumn(name).position(), _currentRow);
|
||||
}
|
||||
|
@@ -168,7 +168,7 @@ protected:
|
||||
const MetaColumn& metaColumn(const std::string& name) const;
|
||||
/// Returns the type for the column with specified name.
|
||||
|
||||
bool isNull(std::size_t col, std::size_t row);
|
||||
bool isNull(std::size_t col, std::size_t row) const;
|
||||
/// Returns true if the current row value at column pos is null.
|
||||
|
||||
private:
|
||||
@@ -272,7 +272,7 @@ inline Statement::Storage Statement::storage() const
|
||||
}
|
||||
|
||||
|
||||
inline bool Statement::isNull(std::size_t col, std::size_t row)
|
||||
inline bool Statement::isNull(std::size_t col, std::size_t row) const
|
||||
{
|
||||
return _ptr->isNull(col, row);
|
||||
}
|
||||
|
@@ -299,7 +299,7 @@ private:
|
||||
addExtract(createExtract<T, std::deque<T> >(mc));
|
||||
}
|
||||
|
||||
bool isNull(std::size_t col, std::size_t row);
|
||||
bool isNull(std::size_t col, std::size_t row) const;
|
||||
/// Returns true if the value in [col, row] is null.
|
||||
|
||||
StatementImpl(const StatementImpl& stmt);
|
||||
@@ -406,7 +406,7 @@ inline bool StatementImpl::isStoredProcedure() const
|
||||
}
|
||||
|
||||
|
||||
inline bool StatementImpl::isNull(std::size_t col, std::size_t row)
|
||||
inline bool StatementImpl::isNull(std::size_t col, std::size_t row) const
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@@ -80,7 +80,7 @@ DynamicAny RecordSet::value(std::size_t col, std::size_t row) const
|
||||
{
|
||||
switch (columnType(col))
|
||||
{
|
||||
case MetaColumn::FDT_BOOL:
|
||||
case MetaColumn::FDT_BOOL: return value<bool>(col, row);
|
||||
case MetaColumn::FDT_INT8: return value<Int8>(col, row);
|
||||
case MetaColumn::FDT_UINT8: return value<UInt8>(col, row);
|
||||
case MetaColumn::FDT_INT16: return value<Int16>(col, row);
|
||||
@@ -104,7 +104,7 @@ DynamicAny RecordSet::value(const std::string& name, std::size_t row) const
|
||||
{
|
||||
switch (columnType(name))
|
||||
{
|
||||
case MetaColumn::FDT_BOOL:
|
||||
case MetaColumn::FDT_BOOL: return value<bool>(name, row);
|
||||
case MetaColumn::FDT_INT8: return value<Int8>(name, row);
|
||||
case MetaColumn::FDT_UINT8: return value<UInt8>(name, row);
|
||||
case MetaColumn::FDT_INT16: return value<Int16>(name, row);
|
||||
|
@@ -289,6 +289,7 @@ void StatementImpl::makeExtractors(Poco::UInt32 count)
|
||||
switch (mc.type())
|
||||
{
|
||||
case MetaColumn::FDT_BOOL:
|
||||
addInternalExtract<bool>(mc); break;
|
||||
case MetaColumn::FDT_INT8:
|
||||
addInternalExtract<Int8>(mc); break;
|
||||
case MetaColumn::FDT_UINT8:
|
||||
|
@@ -423,6 +423,68 @@ void DataTest::testColumnVector()
|
||||
}
|
||||
|
||||
|
||||
void DataTest::testColumnVectorBool()
|
||||
{
|
||||
MetaColumn mc(0, "mc", MetaColumn::FDT_BOOL);
|
||||
|
||||
std::vector<bool>* pData = new std::vector<bool>;
|
||||
pData->push_back(true);
|
||||
pData->push_back(false);
|
||||
pData->push_back(true);
|
||||
pData->push_back(false);
|
||||
pData->push_back(true);
|
||||
|
||||
Column<bool> c(mc, pData);
|
||||
|
||||
assert (c.rowCount() == 5);
|
||||
assert (c[0] == true);
|
||||
assert (c[1] == false);
|
||||
assert (c[2] == true);
|
||||
assert (c[3] == false);
|
||||
assert (c[4] == true);
|
||||
assert (c.type() == MetaColumn::FDT_BOOL);
|
||||
|
||||
try
|
||||
{
|
||||
bool b = c[100];
|
||||
fail ("must fail");
|
||||
}
|
||||
catch (RangeException&) { }
|
||||
|
||||
Column<bool> c1 = c;
|
||||
|
||||
assert (c1.rowCount() == 5);
|
||||
assert (c1[0] == true);
|
||||
assert (c1[1] == false);
|
||||
assert (c1[2] == true);
|
||||
assert (c1[3] == false);
|
||||
assert (c1[4] == true);
|
||||
|
||||
Column<bool> c2(c1);
|
||||
|
||||
assert (c2.rowCount() == 5);
|
||||
assert (c2[0] == true);
|
||||
assert (c2[1] == false);
|
||||
assert (c2[2] == true);
|
||||
assert (c2[3] == false);
|
||||
assert (c2[4] == true);
|
||||
|
||||
std::vector<bool> vi;
|
||||
vi.assign(c.begin(), c.end());
|
||||
assert (vi.size() == 5);
|
||||
assert (vi[0] == true);
|
||||
assert (vi[1] == false);
|
||||
assert (vi[2] == true);
|
||||
assert (vi[3] == false);
|
||||
assert (vi[4] == true);
|
||||
|
||||
c.reset();
|
||||
assert (c.rowCount() == 0);
|
||||
assert (c1.rowCount() == 0);
|
||||
assert (c2.rowCount() == 0);
|
||||
}
|
||||
|
||||
|
||||
void DataTest::testColumnDeque()
|
||||
{
|
||||
typedef std::deque<int> ContainerType;
|
||||
@@ -824,6 +886,7 @@ CppUnit::Test* DataTest::suite()
|
||||
CppUnit_addTest(pSuite, DataTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, DataTest, testBLOBStreams);
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnVector);
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnVectorBool);
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnDeque);
|
||||
CppUnit_addTest(pSuite, DataTest, testColumnList);
|
||||
CppUnit_addTest(pSuite, DataTest, testRow);
|
||||
|
@@ -55,6 +55,7 @@ public:
|
||||
void testBLOB();
|
||||
void testBLOBStreams();
|
||||
void testColumnVector();
|
||||
void testColumnVectorBool();
|
||||
void testColumnDeque();
|
||||
void testColumnList();
|
||||
void testRow();
|
||||
|
Reference in New Issue
Block a user