proper bool support

This commit is contained in:
Aleksandar Fabijanic
2007-09-22 01:20:20 +00:00
parent 40c0f41fa0
commit 228d48ad14
24 changed files with 442 additions and 29 deletions

View File

@@ -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) 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);
} }

View File

@@ -295,7 +295,7 @@ inline void Preparation::prepare(std::size_t pos, Poco::UInt64)
inline void Preparation::prepare(std::size_t pos, bool) inline void Preparation::prepare(std::size_t pos, bool)
{ {
preparePOD<bool>(pos, Utility::boolDataType); preparePOD<bool>(pos, SQL_C_BIT);
} }

View File

@@ -101,9 +101,6 @@ public:
static void dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt); static void dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt);
/// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT. /// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT.
static const SQLSMALLINT boolDataType;
/// ODBC size for bool data type.
private: private:
static const TypeInfo _dataTypes; static const TypeInfo _dataTypes;
/// C <==> SQL data type mapping /// C <==> SQL data type mapping

View File

@@ -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_UINT32: bindNull(pos, SQL_C_ULONG); break;
case NULL_INT64: bindNull(pos, SQL_C_SBIGINT); break; case NULL_INT64: bindNull(pos, SQL_C_SBIGINT); break;
case NULL_UINT64: bindNull(pos, SQL_C_UBIGINT); 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_FLOAT: bindNull(pos, SQL_C_FLOAT); break;
case NULL_DOUBLE: bindNull(pos, SQL_C_DOUBLE); break; case NULL_DOUBLE: bindNull(pos, SQL_C_DOUBLE); break;
case NULL_STRING: bindNull(pos, SQL_C_CHAR); break; case NULL_STRING: bindNull(pos, SQL_C_CHAR); break;

View File

@@ -358,7 +358,7 @@ bool Extractor::extract(std::size_t pos, Poco::UInt64& val)
bool Extractor::extract(std::size_t pos, bool& val) bool Extractor::extract(std::size_t pos, bool& val)
{ {
if (Preparation::DE_MANUAL == _dataExtraction) if (Preparation::DE_MANUAL == _dataExtraction)
return extractManualImpl(pos, val, Utility::boolDataType); return extractManualImpl(pos, val, SQL_C_BIT);
else else
return extractBoundImpl(pos, val); return extractBoundImpl(pos, val);
} }

View File

@@ -101,6 +101,8 @@ void ODBCColumn::init()
setNullable(SQL_NULLABLE == _columnDesc.isNullable); setNullable(SQL_NULLABLE == _columnDesc.isNullable);
switch(_columnDesc.dataType) switch(_columnDesc.dataType)
{ {
case SQL_BIT:
setType(MetaColumn::FDT_BOOL); break;
case SQL_CHAR: case SQL_CHAR:
case SQL_VARCHAR: case SQL_VARCHAR:
case SQL_LONGVARCHAR: case SQL_LONGVARCHAR:

View File

@@ -125,7 +125,7 @@ void Preparation::prepare(std::size_t pos, const Poco::Any&)
return preparePOD<Poco::UInt64>(pos, SQL_C_UBIGINT); return preparePOD<Poco::UInt64>(pos, SQL_C_UBIGINT);
case MetaColumn::FDT_BOOL: case MetaColumn::FDT_BOOL:
return preparePOD<bool>(pos, Utility::boolDataType); return preparePOD<bool>(pos, SQL_C_BIT);
case MetaColumn::FDT_FLOAT: case MetaColumn::FDT_FLOAT:
return preparePOD<float>(pos, SQL_C_FLOAT); return preparePOD<float>(pos, SQL_C_FLOAT);

View File

@@ -48,8 +48,6 @@ namespace ODBC {
const TypeInfo Utility::_dataTypes; 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) Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap)

View File

@@ -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() void ODBCPostgreSQLTest::configurePLPgSQL()
{ {
if (!_pSession) fail ("Test not available."); 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) bool ODBCPostgreSQLTest::canConnect(const std::string& driver, const std::string& dsn)
{ {
Utility::DriverMap::iterator itDrv = _drivers.begin(); Utility::DriverMap::iterator itDrv = _drivers.begin();
@@ -1285,6 +1316,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStoredFunction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNull); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNull);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testRowIterator); CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testRowIterator);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testStdVectorBool);
return pSuite; return pSuite;
} }

View File

@@ -45,7 +45,7 @@
// uncomment to use Mammoth ODBCng driver // uncomment to use Mammoth ODBCng driver
//#define POCO_ODBC_USE_MAMMOTH_NG #define POCO_ODBC_USE_MAMMOTH_NG
class ODBCPostgreSQLTest: public CppUnit::TestCase class ODBCPostgreSQLTest: public CppUnit::TestCase
@@ -131,6 +131,7 @@ public:
void testStoredFunction(); void testStoredFunction();
void testNull(); void testNull();
void testRowIterator(); void testRowIterator();
void testStdVectorBool();
void setUp(); void setUp();
void tearDown(); void tearDown();
@@ -152,6 +153,7 @@ private:
void recreateTuplesTable(); void recreateTuplesTable();
void recreateVectorsTable(); void recreateVectorsTable();
void recreateNullsTable(const std::string& notNull=""); void recreateNullsTable(const std::string& notNull="");
void recreateBoolTable();
static bool init(const std::string& driver, const std::string& dsn); static bool init(const std::string& driver, const std::string& dsn);
static bool canConnect(const std::string& driver, const std::string& dsn); static bool canConnect(const std::string& driver, const std::string& dsn);

View File

@@ -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) void ODBCSQLServerTest::dropObject(const std::string& type, const std::string& name)
{ {
try try
@@ -1190,6 +1205,14 @@ void ODBCSQLServerTest::recreateNullsTable(const std::string& notNull)
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateNullsTable()"); } 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) 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, testInternalStorageType);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull); CppUnit_addTest(pSuite, ODBCSQLServerTest, testNull);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator); CppUnit_addTest(pSuite, ODBCSQLServerTest, testRowIterator);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testStdVectorBool);
return pSuite; return pSuite;
} }

View File

@@ -127,6 +127,7 @@ public:
void testNull(); void testNull();
void testRowIterator(); void testRowIterator();
void testStdVectorBool();
void setUp(); void setUp();
void tearDown(); void tearDown();
@@ -149,6 +150,7 @@ private:
void recreateVectorTable(); void recreateVectorTable();
void recreateVectorsTable(); void recreateVectorsTable();
void recreateNullsTable(const std::string& notNull = ""); void recreateNullsTable(const std::string& notNull = "");
void recreateBoolTable();
static bool init(const std::string& driver, const std::string& dsn); static bool init(const std::string& driver, const std::string& dsn);
static bool canConnect(const std::string& driver, const std::string& dsn); static bool canConnect(const std::string& driver, const std::string& dsn);

View File

@@ -2152,7 +2152,7 @@ void SQLExecutor::nulls()
void SQLExecutor::rowIterator() void SQLExecutor::rowIterator()
{ {
std::string funct = "internalExtraction()"; std::string funct = "rowIterator()";
std::vector<Tuple<int, double, std::string> > v; 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>(1, 1.5f, "3"));
v.push_back(Tuple<int, double, std::string>(2, 2.5f, "4")); 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)); std::copy(rset.begin(), rset.end(), std::ostream_iterator<Row>(osCopy));
assert (osLoop.str() == osCopy.str()); 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);
}

View File

@@ -132,6 +132,7 @@ public:
void nulls(); void nulls();
void notNulls(const std::string& sqlState = "23502"); void notNulls(const std::string& sqlState = "23502");
void rowIterator(); void rowIterator();
void stdVectorBool();
private: private:
Poco::Data::Session* _pSession; Poco::Data::Session* _pSession;

View File

@@ -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> template <class T>
class Binding<std::list<T> >: public AbstractBinding class Binding<std::list<T> >: public AbstractBinding
/// Specialization for std::list. /// Specialization for std::list.

View File

@@ -45,6 +45,7 @@
#include "Poco/SharedPtr.h" #include "Poco/SharedPtr.h"
#include <vector> #include <vector>
#include <list> #include <list>
#include <deque>
namespace Poco { 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> template <class T>
class Column<T, std::list<T> > class Column<T, std::list<T> >
/// Column specialization for std::list /// Column specialization for std::list

View File

@@ -171,8 +171,13 @@ public:
void extract(std::size_t pos) void extract(std::size_t pos)
{ {
AbstractExtractor* pExt = getExtractor(); 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)); _nulls.push_back(pExt->isNull(pos));
} }

View File

@@ -180,25 +180,25 @@ public:
/// Returns the data value at named column, row location. /// Returns the data value at named column, row location.
template <typename C> 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 /// Returns the value in the named column of the current row
/// if the value is not NULL, or deflt otherwise. /// if the value is not NULL, or deflt otherwise.
{ {
if (isNull(name)) if (isNull(name))
return DynamicAny(deflt); return deflt;
else else
return value(name); return value<C>(name, _currentRow);
} }
template <typename C> 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 /// Returns the value in the given column of the current row
/// if the value is not NULL, or deflt otherwise. /// if the value is not NULL, or deflt otherwise.
{ {
if (isNull(index)) if (isNull(index))
return DynamicAny(deflt); return deflt;
else else
return value(index); return value<C>(index, _currentRow);
} }
const RowIterator& begin(); const RowIterator& begin();
@@ -267,7 +267,7 @@ public:
/// Returns column precision for the column with specified name. /// Returns column precision for the column with specified name.
/// Valid for floating point fields only (zero for other data types). /// 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. /// Returns true if column value of the current row is null.
private: 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); return isNull(metaColumn(name).position(), _currentRow);
} }

View File

@@ -168,7 +168,7 @@ protected:
const MetaColumn& metaColumn(const std::string& name) const; const MetaColumn& metaColumn(const std::string& name) const;
/// Returns the type for the column with specified name. /// 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. /// Returns true if the current row value at column pos is null.
private: 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); return _ptr->isNull(col, row);
} }

View File

@@ -299,7 +299,7 @@ private:
addExtract(createExtract<T, std::deque<T> >(mc)); 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. /// Returns true if the value in [col, row] is null.
StatementImpl(const StatementImpl& stmt); 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 try
{ {

View File

@@ -80,7 +80,7 @@ DynamicAny RecordSet::value(std::size_t col, std::size_t row) const
{ {
switch (columnType(col)) 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_INT8: return value<Int8>(col, row);
case MetaColumn::FDT_UINT8: return value<UInt8>(col, row); case MetaColumn::FDT_UINT8: return value<UInt8>(col, row);
case MetaColumn::FDT_INT16: return value<Int16>(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)) 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_INT8: return value<Int8>(name, row);
case MetaColumn::FDT_UINT8: return value<UInt8>(name, row); case MetaColumn::FDT_UINT8: return value<UInt8>(name, row);
case MetaColumn::FDT_INT16: return value<Int16>(name, row); case MetaColumn::FDT_INT16: return value<Int16>(name, row);

View File

@@ -289,6 +289,7 @@ void StatementImpl::makeExtractors(Poco::UInt32 count)
switch (mc.type()) switch (mc.type())
{ {
case MetaColumn::FDT_BOOL: case MetaColumn::FDT_BOOL:
addInternalExtract<bool>(mc); break;
case MetaColumn::FDT_INT8: case MetaColumn::FDT_INT8:
addInternalExtract<Int8>(mc); break; addInternalExtract<Int8>(mc); break;
case MetaColumn::FDT_UINT8: case MetaColumn::FDT_UINT8:

View File

@@ -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() void DataTest::testColumnDeque()
{ {
typedef std::deque<int> ContainerType; typedef std::deque<int> ContainerType;
@@ -824,6 +886,7 @@ CppUnit::Test* DataTest::suite()
CppUnit_addTest(pSuite, DataTest, testBLOB); CppUnit_addTest(pSuite, DataTest, testBLOB);
CppUnit_addTest(pSuite, DataTest, testBLOBStreams); CppUnit_addTest(pSuite, DataTest, testBLOBStreams);
CppUnit_addTest(pSuite, DataTest, testColumnVector); CppUnit_addTest(pSuite, DataTest, testColumnVector);
CppUnit_addTest(pSuite, DataTest, testColumnVectorBool);
CppUnit_addTest(pSuite, DataTest, testColumnDeque); CppUnit_addTest(pSuite, DataTest, testColumnDeque);
CppUnit_addTest(pSuite, DataTest, testColumnList); CppUnit_addTest(pSuite, DataTest, testColumnList);
CppUnit_addTest(pSuite, DataTest, testRow); CppUnit_addTest(pSuite, DataTest, testRow);

View File

@@ -55,6 +55,7 @@ public:
void testBLOB(); void testBLOB();
void testBLOBStreams(); void testBLOBStreams();
void testColumnVector(); void testColumnVector();
void testColumnVectorBool();
void testColumnDeque(); void testColumnDeque();
void testColumnList(); void testColumnList();
void testRow(); void testRow();