Skip to content

Commit fc5a503

Browse files
committed
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.
1 parent 3e65280 commit fc5a503

21 files changed

Lines changed: 435 additions & 106 deletions

‎Data/ODBC/include/Poco/Data/ODBC/Diagnostics.h‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class Diagnostics
7979
typedef std::vector<DiagnosticFields> FieldVec;
8080
typedef typename FieldVec::const_iterator Iterator;
8181

82-
explicit Diagnostics(H& rHandle): _rHandle(rHandle)
82+
explicit Diagnostics(const H& handle): _handle(handle)
8383
/// Creates and initializes the Diagnostics.
8484
{
8585
std::memset(_connectionName, 0, sizeof(_connectionName));
@@ -169,7 +169,7 @@ class Diagnostics
169169
reset();
170170

171171
while (!Utility::isError(SQLGetDiagRec(handleType,
172-
_rHandle,
172+
_handle,
173173
count,
174174
df._sqlState,
175175
&df._nativeError,
@@ -183,7 +183,7 @@ class Diagnostics
183183
// (they fail if connection has not been established yet
184184
// or return empty string if not applicable for the context)
185185
if (Utility::isError(SQLGetDiagField(handleType,
186-
_rHandle,
186+
_handle,
187187
count,
188188
SQL_DIAG_CONNECTION_NAME,
189189
_connectionName,
@@ -202,7 +202,7 @@ class Diagnostics
202202
}
203203

204204
if (Utility::isError(SQLGetDiagField(handleType,
205-
_rHandle,
205+
_handle,
206206
count,
207207
SQL_DIAG_SERVER_NAME,
208208
_serverName,
@@ -245,7 +245,7 @@ class Diagnostics
245245
FieldVec _fields;
246246

247247
/// Context handle
248-
H& _rHandle;
248+
const H& _handle;
249249
};
250250

251251

‎Data/ODBC/include/Poco/Data/ODBC/Error.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class Error
6363
/// as well as individual diagnostic records.
6464
{
6565
public:
66-
explicit Error(H handle) : _diagnostics(handle)
66+
explicit Error(const H& handle) : _diagnostics(handle)
6767
/// Creates the Error.
6868
{
6969
}

‎Data/ODBC/include/Poco/Data/ODBC/Extractor.h‎

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
4848
#include "Poco/Data/ODBC/Error.h"
4949
#include "Poco/Data/ODBC/Utility.h"
50+
#include "Poco/Data/Date.h"
51+
#include "Poco/Data/Time.h"
5052
#include "Poco/DateTime.h"
5153
#include "Poco/Any.h"
5254
#include "Poco/DynamicAny.h"
@@ -398,6 +400,15 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
398400
return true;
399401
}
400402

403+
template <typename T, typename NT>
404+
bool extAny(std::size_t pos, T& val)
405+
{
406+
NT i;
407+
extract(pos, i);
408+
val = i;
409+
return true;
410+
}
411+
401412
template <typename T>
402413
bool extractImpl(std::size_t pos, T& val)
403414
/// Utility function for extraction of Any and DynamicAny.
@@ -407,46 +418,52 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor
407418
switch (column.type())
408419
{
409420
case MetaColumn::FDT_INT8:
410-
{ Poco::Int8 i = 0; extract(pos, i); val = i; return true; }
421+
{ return extAny<T, Poco::Int8>(pos, val); }
411422

412423
case MetaColumn::FDT_UINT8:
413-
{ Poco::UInt8 i = 0; extract(pos, i); val = i; return true; }
424+
{ return extAny<T, Poco::UInt8>(pos, val); }
414425

415426
case MetaColumn::FDT_INT16:
416-
{ Poco::Int16 i = 0; extract(pos, i); val = i; return true; }
427+
{ return extAny<T, Poco::Int16>(pos, val); }
417428

418429
case MetaColumn::FDT_UINT16:
419-
{ Poco::UInt16 i = 0; extract(pos, i); val = i; return true; }
430+
{ return extAny<T, Poco::UInt16>(pos, val); }
420431

421432
case MetaColumn::FDT_INT32:
422-
{ Poco::Int32 i = 0; extract(pos, i); val = i; return true; }
433+
{ return extAny<T, Poco::Int32>(pos, val); }
423434

424435
case MetaColumn::FDT_UINT32:
425-
{ Poco::UInt32 i = 0; extract(pos, i); val = i; return true; }
436+
{ return extAny<T, Poco::UInt32>(pos, val); }
426437

427438
case MetaColumn::FDT_INT64:
428-
{ Poco::Int64 i = 0; extract(pos, i); val = i; return true; }
439+
{ return extAny<T, Poco::Int64>(pos, val); }
429440

430441
case MetaColumn::FDT_UINT64:
431-
{ Poco::UInt64 i = 0; extract(pos, i); val = i; return true; }
442+
{ return extAny<T, Poco::UInt64>(pos, val); }
432443

433444
case MetaColumn::FDT_BOOL:
434-
{ bool b; extract(pos, b); val = b; return true; }
445+
{ return extAny<T, bool>(pos, val); }
435446

436447
case MetaColumn::FDT_FLOAT:
437-
{ float f; extract(pos, f); val = f; return true; }
448+
{ return extAny<T, float>(pos, val); }
438449

439450
case MetaColumn::FDT_DOUBLE:
440-
{ double d; extract(pos, d); val = d; return true; }
451+
{ return extAny<T, double>(pos, val); }
441452

442453
case MetaColumn::FDT_STRING:
443-
{ std::string s; extract(pos, s); val = s; return true; }
454+
{ return extAny<T, std::string>(pos, val); }
444455

445456
case MetaColumn::FDT_BLOB:
446-
{ Poco::Data::BLOB b; extract(pos, b); val = b; return true; }
457+
{ return extAny<T, Poco::Data::BLOB>(pos, val); }
458+
459+
case MetaColumn::FDT_DATE:
460+
{ return extAny<T, Poco::Data::Date>(pos, val); }
461+
462+
case MetaColumn::FDT_TIME:
463+
{ return extAny<T, Poco::Data::Time>(pos, val); }
447464

448465
case MetaColumn::FDT_TIMESTAMP:
449-
{ Poco::DateTime b; extract(pos, b); val = b; return true; }
466+
{ return extAny<T, Poco::DateTime>(pos, val); }
450467

451468
default:
452469
throw DataFormatException("Unsupported data type.");

‎Data/ODBC/src/Binder.cpp‎

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,17 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
128128
}
129129
else if (isInBound(dir))
130130
{
131-
if (size) pVal = (SQLPOINTER) val.c_str();
131+
pVal = (SQLPOINTER) val.c_str();
132132
_inParams.insert(ParamMap::value_type(pVal, size));
133133
}
134134
else
135135
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
136136

137137
SQLLEN* pLenIn = new SQLLEN;
138-
if (0 != size) *pLenIn = SQL_NTS;
139-
else
140-
{
141-
*pLenIn = SQL_NULL_DATA;
142-
SQLINTEGER colSize = 0;
143-
SQLSMALLINT decDigits = 0;
144-
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
145-
size = colSize;
146-
}
138+
SQLINTEGER colSize = 0;
139+
SQLSMALLINT decDigits = 0;
140+
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
141+
*pLenIn = SQL_NTS;
147142

148143
if (PB_AT_EXEC == _paramBinding)
149144
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
@@ -155,7 +150,7 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
155150
toODBCDirection(dir),
156151
SQL_C_CHAR,
157152
SQL_LONGVARCHAR,
158-
(SQLUINTEGER) size,
153+
(SQLUINTEGER) colSize,
159154
0,
160155
pVal,
161156
(SQLINTEGER) size,
@@ -177,16 +172,7 @@ void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
177172
_inParams.insert(ParamMap::value_type(pVal, size));
178173

179174
SQLLEN* pLenIn = new SQLLEN;
180-
181-
if (0 != size) *pLenIn = size;
182-
else
183-
{
184-
*pLenIn = SQL_NULL_DATA;
185-
SQLINTEGER colSize = 0;
186-
SQLSMALLINT decDigits = 0;
187-
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
188-
size = colSize;
189-
}
175+
*pLenIn = size;
190176

191177
if (PB_AT_EXEC == _paramBinding)
192178
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
@@ -200,7 +186,7 @@ void Binder::bind(std::size_t pos, const BLOB& val, Direction dir)
200186
SQL_LONGVARBINARY,
201187
(SQLUINTEGER) size,
202188
0,
203-
pVal,
189+
pVal,
204190
(SQLINTEGER) size,
205191
_lengthIndicator.back())))
206192
{

‎Data/ODBC/src/Extractor.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,8 +1274,8 @@ bool Extractor::isNull(std::size_t col, std::size_t row)
12741274
try
12751275
{
12761276
return isNullLengthIndicator(_lengths.at(col));
1277-
}catch (std::out_of_range& ex)
1278-
{
1277+
} catch (std::out_of_range& ex)
1278+
{
12791279
throw RangeException(ex.what());
12801280
}
12811281
}

‎Data/ODBC/src/ODBCStatementImpl.cpp‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,19 @@ void ODBCStatementImpl::putData()
242242

243243
while (SQL_NEED_DATA == (rc = SQLParamData(_stmt, &pParam)))
244244
{
245-
poco_assert_dbg (pParam);
246-
dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
245+
if (pParam)
246+
{
247+
dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
247248

248-
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
249-
throw StatementException(_stmt, "SQLPutData()");
250-
249+
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
250+
throw StatementException(_stmt, "SQLPutData()");
251+
}
252+
else // if pParam is null pointer, do a dummy call
253+
{
254+
char dummy = 0;
255+
if (Utility::isError(SQLPutData(_stmt, &dummy, 0)))
256+
throw StatementException(_stmt, "SQLPutData()");
257+
}
251258
}
252259

253260
checkError(rc, "SQLParamData()");

‎Data/ODBC/src/Utility.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Utility::DriverMap& Utility::drivers(Utility::DriverMap& driverMap)
8080
}
8181

8282
if (SQL_NO_DATA != rc)
83-
throw EnvironmentError(henv);
83+
throw EnvironmentException(henv);
8484

8585
return driverMap;
8686
}
@@ -116,7 +116,7 @@ Utility::DSNMap& Utility::dataSources(Utility::DSNMap& dsnMap)
116116
}
117117

118118
if (SQL_NO_DATA != rc)
119-
throw EnvironmentError(henv);
119+
throw EnvironmentException(henv);
120120

121121
return dsnMap;
122122
}

‎Data/ODBC/testsuite/src/SQLExecutor.cpp‎

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2682,10 +2682,10 @@ void SQLExecutor::nulls()
26822682
assert (1 == rs.rowCount());
26832683
rs.moveFirst();
26842684
assert (rs.isNull("i"));
2685-
assert (rs["i"] == 0);
2685+
assert (rs["i"] != 0);
26862686
assert (rs.isNull("r"));
26872687
assert (rs.isNull("v"));
2688-
assert (rs["v"] == "");
2688+
assert (rs["v"] != "");
26892689
try { session() << "DELETE FROM NullTest", now; }
26902690
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
26912691
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
@@ -2721,14 +2721,57 @@ void SQLExecutor::nulls()
27212721
assert (rs["i"] == 1);
27222722
assert (!rs.isNull("r"));
27232723
assert (rs.isNull("v"));
2724-
assert (rs["v"] == "");
2724+
assert (rs["v"] != "");
27252725

27262726
assert (rs.moveNext());
27272727
assert (!rs.isNull("i"));
27282728
assert (rs["i"] == 2);
27292729
assert (rs.isNull("r"));
27302730
assert (rs.isNull("v"));
2731-
assert (rs["v"] == "");
2731+
assert (rs["v"] != "");
2732+
2733+
try { session() << "DELETE FROM NullTest", now; }
2734+
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
2735+
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
2736+
2737+
try { session() << "INSERT INTO NullTest (v) VALUES (?)", bind(""), now; }
2738+
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
2739+
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
2740+
2741+
bool esin = session().getFeature("emptyStringIsNull");
2742+
session().setFeature("emptyStringIsNull", true);
2743+
2744+
try
2745+
{
2746+
session().setFeature("forceEmptyString", true);
2747+
fail ("must fail");
2748+
} catch (InvalidAccessException&) { }
2749+
2750+
bool fes = session().getFeature("forceEmptyString");
2751+
session().setFeature("forceEmptyString", false);
2752+
2753+
RecordSet rs1(session(), "SELECT v FROM NullTest");
2754+
assert (1 == rs1.rowCount());
2755+
rs1.moveFirst();
2756+
assert (rs1.isNull("v"));
2757+
assert (!(rs["v"] == ""));
2758+
2759+
session().setFeature("emptyStringIsNull", false);
2760+
session().setFeature("forceEmptyString", true);
2761+
RecordSet rs2(session(), "SELECT v FROM NullTest");
2762+
assert (1 == rs2.rowCount());
2763+
rs2.moveFirst();
2764+
assert (!rs2.isNull("v"));
2765+
assert ((rs2["v"] == ""));
2766+
2767+
try
2768+
{
2769+
session().setFeature("emptyStringIsNull", true);
2770+
fail ("must fail");
2771+
} catch (InvalidAccessException&) { }
2772+
2773+
session().setFeature("emptyStringIsNull", esin);
2774+
session().setFeature("forceEmptyString", fes);
27322775
}
27332776

27342777

0 commit comments

Comments
 (0)