Changes related to following tracker items:

[2025916] ODBC binds empty string as null?
[2000408] DynamicAny non-initialized state support
[1981130] pointless comparison of unsigned integer with zero

and some refactoring.

Warning: only tested on Windows.
This commit is contained in:
Aleksandar Fabijanic
2008-07-29 20:11:38 +00:00
parent 3e65280dc1
commit fc5a503593
21 changed files with 435 additions and 106 deletions

View File

@@ -129,11 +129,44 @@ public:
bool isBulk() const;
/// Returns true if this is bulk extraction.
void setEmptyStringIsNull(bool emptyStringIsNull);
/// Sets the empty string handling flag.
bool getEmptyStringIsNull() const;
/// Returns the empty string handling flag.
void setForceEmptyString(bool forceEmptyString);
/// Sets the force empty string flag.
bool getForceEmptyString() const;
/// Returns the force empty string flag.
template <typename T>
bool isValueNull(const T& str, bool deflt)
/// Utility function to determine the nullness of the value.
/// This generic version always returns default value
/// (i.e. does nothing).
///
{
return deflt;
}
template <>
bool isValueNull(const std::string& str, bool deflt);
/// Specialization for const reference to std::string.
///
/// Returns true when folowing conditions are met:
///
/// - string is empty
/// - getEmptyStringIsNull() returns true
private:
AbstractExtractor* _pExtractor;
Poco::UInt32 _limit;
Poco::UInt32 _position;
bool _bulk;
bool _emptyStringIsNull;
bool _forceEmptyString;
};
@@ -202,6 +235,30 @@ inline bool AbstractExtraction::canExtract() const
}
inline void AbstractExtraction::setEmptyStringIsNull(bool emptyStringIsNull)
{
_emptyStringIsNull = emptyStringIsNull;
}
inline bool AbstractExtraction::getEmptyStringIsNull() const
{
return _emptyStringIsNull;
}
inline void AbstractExtraction::setForceEmptyString(bool forceEmptyString)
{
_forceEmptyString = forceEmptyString;
}
inline bool AbstractExtraction::getForceEmptyString() const
{
return _forceEmptyString;
}
} } // namespace Poco::Data

View File

@@ -72,7 +72,10 @@ public:
typedef Poco::Any (C::*PropertyGetter)(const std::string&);
/// The getter method for a property.
AbstractSessionImpl()
AbstractSessionImpl(): _storage(std::string("deque")),
_bulk(false),
_emptyStringIsNull(false),
_forceEmptyString(false)
/// Creates the AbstractSessionImpl.
///
/// Adds "storage" property and sets the default internal storage container
@@ -83,22 +86,41 @@ public:
/// duration of the session) and locally (for a single statement execution only).
/// See StatementImpl for details on how this property is used at runtime.
///
/// Adds bulk feature and sets it to false.
/// Adds "bulk" feature and sets it to false.
/// Bulk feature determines whether the session is capable of bulk operations.
/// Connectors that are capable of it must set this feature prior to attempting
/// bulk operations.
///
/// Adds "emptyStringIsNull" feature and sets it to false. This feature should be
/// set to true in order to modify the behavior of the databases that distinguish
/// between zero-length character strings as nulls. Setting this feature to true
/// shall disregard any difference between empty character strings and nulls,
/// causing the framework to treat them the same (i.e. behave like Oracle).
///
/// Adds "forceEmptyString" feature and sets it to false. This feature should be set
/// to true in order to force the databases that do not distinguish empty strings from
/// nulls (e.g. Oracle) to always report empty string.
///
/// The "emptyStringIsNull" and "forceEmptyString" features are mutually exclusive.
/// While these features can not both be true at the same time, they can both be false,
/// resulting in default underlying database behavior.
///
{
addProperty("storage",
&AbstractSessionImpl<C>::setStorage,
&AbstractSessionImpl<C>::getStorage);
setProperty("storage", std::string("deque"));
addFeature("bulk",
&AbstractSessionImpl<C>::setBulk,
&AbstractSessionImpl<C>::getBulk);
setFeature("bulk", false);
addFeature("emptyStringIsNull",
&AbstractSessionImpl<C>::setEmptyStringIsNull,
&AbstractSessionImpl<C>::getEmptyStringIsNull);
addFeature("forceEmptyString",
&AbstractSessionImpl<C>::setForceEmptyString,
&AbstractSessionImpl<C>::getForceEmptyString);
}
~AbstractSessionImpl()
@@ -196,6 +218,47 @@ public:
return _bulk;
}
void setEmptyStringIsNull(const std::string& name, bool emptyStringIsNull)
/// Sets the behavior regarding empty variable length strings.
/// Those are treated as NULL by Oracle and as empty string by
/// most other databases.
/// When this feature is true, empty strings are treated as NULL.
{
if (emptyStringIsNull && _forceEmptyString)
throw InvalidAccessException("Features mutually exclusive");
_emptyStringIsNull = emptyStringIsNull;
}
bool getEmptyStringIsNull(const std::string& name="")
/// Returns the setting for the behavior regarding empty variable
/// length strings. See setEmptyStringIsNull(const std::string&, bool)
/// and this class documentation for feature rationale and details.
{
return _emptyStringIsNull;
}
void setForceEmptyString(const std::string& name, bool forceEmptyString)
/// Sets the behavior regarding empty variable length strings.
/// Those are treated as NULL by Oracle and as empty string by
/// most other databases.
/// When this feature is true, both empty strings and NULL values
/// are reported as empty strings.
{
if (forceEmptyString && _emptyStringIsNull)
throw InvalidAccessException("Features mutually exclusive");
_forceEmptyString = forceEmptyString;
}
bool getForceEmptyString(const std::string& name="")
/// Returns the setting for the behavior regarding empty variable
/// length strings. See setForceEmptyString(const std::string&, bool)
/// and this class documentation for feature rationale and details.
{
return _forceEmptyString;
}
protected:
void addFeature(const std::string& name, FeatureSetter setter, FeatureGetter getter)
/// Adds a feature to the map of supported features.
@@ -241,6 +304,8 @@ private:
PropertyMap _properties;
std::string _storage;
bool _bulk;
bool _emptyStringIsNull;
bool _forceEmptyString;
};

View File

@@ -117,7 +117,9 @@ public:
typename C::iterator it = _rResult.begin();
typename C::iterator end = _rResult.end();
for (int row = 0; it !=end; ++it, ++row)
_nulls.push_back(pExt->isNull(col, row));
{
_nulls.push_back(isValueNull(*it, pExt->isNull(col, row)));
}
return _rResult.size();
}

View File

@@ -115,7 +115,8 @@ public:
_extracted = true;
AbstractExtractor* pExt = getExtractor();
TypeHandler<T>::extract(pos, _rResult, _default, pExt);
_null = pExt->isNull(pos);
_null = isValueNull<T>(_rResult, pExt->isNull(pos));
return 1u;
}
@@ -199,7 +200,7 @@ public:
AbstractExtractor* pExt = getExtractor();
_rResult.push_back(_default);
TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt);
_nulls.push_back(pExt->isNull(pos));
_nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos)));
return 1u;
}
@@ -359,7 +360,7 @@ public:
AbstractExtractor* pExt = getExtractor();
_rResult.push_back(_default);
TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt);
_nulls.push_back(pExt->isNull(pos));
_nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos)));
return 1u;
}
@@ -438,7 +439,7 @@ public:
AbstractExtractor* pExt = getExtractor();
_rResult.push_back(_default);
TypeHandler<T>::extract(pos, _rResult.back(), _default, pExt);
_nulls.push_back(pExt->isNull(pos));
_nulls.push_back(isValueNull(_rResult.back(), pExt->isNull(pos)));
return 1u;
}

View File

@@ -42,9 +42,6 @@
#include "Poco/Data/AbstractBinder.h"
#include <iostream>
//using namespace Poco::Data::Keywords;
//using Poco::Data::NullData;
namespace Poco {
namespace Data {
@@ -124,7 +121,7 @@ public:
}
bool operator < (const Nullable<T>& other) const
/// Compares two Nullable
/// Compares two Nullable objects
{
if (_isNull < other._isNull)
return true;
@@ -132,13 +129,13 @@ public:
}
operator T& ()
/// Get referens to value
/// Get reference to the value
{
return _value;
}
operator const T& () const
/// Get const referens to value
/// Get const reference to the value
{
return _value;
}