mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-29 12:18:01 +01:00
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:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user