mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-27 02:53:10 +01:00
This commit is contained in:
@@ -68,8 +68,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef AbstractBinder::Direction Direction;
|
typedef AbstractBinder::Direction Direction;
|
||||||
typedef Tuple<SQLPOINTER, SQLLEN, SQLSMALLINT, SQLSMALLINT> ParamTuple;
|
typedef std::map<SQLPOINTER, SQLLEN> ParamMap;
|
||||||
typedef std::vector<ParamTuple> ParamVec;
|
|
||||||
|
|
||||||
static const size_t DEFAULT_PARAM_SIZE = 1024;
|
static const size_t DEFAULT_PARAM_SIZE = 1024;
|
||||||
|
|
||||||
@@ -145,14 +144,10 @@ public:
|
|||||||
/// Transfers the results of non-POD outbound parameters from internal
|
/// Transfers the results of non-POD outbound parameters from internal
|
||||||
/// holders back into the externally supplied buffers.
|
/// holders back into the externally supplied buffers.
|
||||||
|
|
||||||
ParamVec& outParameters();
|
|
||||||
/// Returns map of output parameter pointers and sizes.
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<SQLLEN*> LengthVec;
|
typedef std::vector<SQLLEN*> LengthVec;
|
||||||
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
||||||
typedef std::map<char*, std::string*> StringMap;
|
typedef std::map<char*, std::string*> StringMap;
|
||||||
typedef std::map<char*, BLOB*> BLOBMap;
|
|
||||||
|
|
||||||
void describeParameter(std::size_t pos);
|
void describeParameter(std::size_t pos);
|
||||||
/// Sets the description field for the parameter, if needed.
|
/// Sets the description field for the parameter, if needed.
|
||||||
@@ -204,12 +199,11 @@ private:
|
|||||||
|
|
||||||
const StatementHandle& _rStmt;
|
const StatementHandle& _rStmt;
|
||||||
LengthVec _lengthIndicator;
|
LengthVec _lengthIndicator;
|
||||||
ParamVec _inParams;
|
ParamMap _inParams;
|
||||||
ParamVec _outParams;
|
ParamMap _outParams;
|
||||||
ParameterBinding _paramBinding;
|
ParameterBinding _paramBinding;
|
||||||
TimestampMap _timestamps;
|
TimestampMap _timestamps;
|
||||||
StringMap _strings;
|
StringMap _strings;
|
||||||
BLOBMap _blobs;
|
|
||||||
const TypeInfo* _pTypeInfo;
|
const TypeInfo* _pTypeInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,24 +295,6 @@ inline Binder::ParameterBinding Binder::getDataBinding() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Binder::ParamVec& Binder::outParameters()
|
|
||||||
{
|
|
||||||
return _outParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t Binder::getParamSize(std::size_t pos)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Parameter(_rStmt, pos).columnSize();
|
|
||||||
}catch (StatementException&)
|
|
||||||
{
|
|
||||||
return DEFAULT_PARAM_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
} } } // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,10 +71,6 @@ Binder::~Binder()
|
|||||||
StringMap::iterator itStr = _strings.begin();
|
StringMap::iterator itStr = _strings.begin();
|
||||||
StringMap::iterator itStrEnd = _strings.end();
|
StringMap::iterator itStrEnd = _strings.end();
|
||||||
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
|
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
|
||||||
|
|
||||||
BLOBMap::iterator itB = _blobs.begin();
|
|
||||||
BLOBMap::iterator itBEnd = _blobs.end();
|
|
||||||
for(; itB != itBEnd; ++itB) std::free(itB->first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -86,18 +82,16 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
|||||||
if (isOutBound(dir))
|
if (isOutBound(dir))
|
||||||
{
|
{
|
||||||
Parameter p(_rStmt, pos);
|
Parameter p(_rStmt, pos);
|
||||||
size = p.columnSize();
|
size = (SQLINTEGER) p.columnSize();
|
||||||
char* pChar = (char*) std::calloc(size, sizeof(char));
|
char* pChar = (char*) std::calloc(size, sizeof(char));
|
||||||
ParamTuple pt(pChar, size, SQL_C_CHAR, SQL_LONGVARCHAR);
|
|
||||||
_outParams.push_back(pt);
|
|
||||||
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
|
|
||||||
pVal = (SQLPOINTER) pChar;
|
pVal = (SQLPOINTER) pChar;
|
||||||
|
_outParams.insert(ParamMap::value_type(pVal, size));
|
||||||
|
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
|
||||||
}
|
}
|
||||||
else if (isInBound(dir))
|
else if (isInBound(dir))
|
||||||
{
|
{
|
||||||
pVal = (SQLPOINTER) val.c_str();
|
pVal = (SQLPOINTER) val.c_str();
|
||||||
ParamTuple pt((SQLPOINTER) pVal, size, SQL_C_CHAR, SQL_LONGVARCHAR);
|
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||||
_inParams.push_back(pt);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw IllegalStateException("Parameter must be [in] OR [out] bound.");
|
throw IllegalStateException("Parameter must be [in] OR [out] bound.");
|
||||||
@@ -128,26 +122,13 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
|
|||||||
|
|
||||||
void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir)
|
void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir)
|
||||||
{
|
{
|
||||||
SQLPOINTER pVal = 0;
|
if (isOutBound(dir) || !isInBound(dir))
|
||||||
|
throw NotImplementedException("BLOB parameter type can only be inbound.");
|
||||||
|
|
||||||
|
SQLPOINTER pVal = (SQLPOINTER) val.rawContent();
|
||||||
SQLINTEGER size = (SQLINTEGER) val.size();
|
SQLINTEGER size = (SQLINTEGER) val.size();
|
||||||
|
|
||||||
if (isOutBound(dir))
|
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||||
{
|
|
||||||
size = getParamSize(pos);
|
|
||||||
char* pChar = (char*) std::calloc(size, sizeof(char));
|
|
||||||
ParamTuple pt(pChar, size, SQL_C_BINARY, SQL_LONGVARBINARY);
|
|
||||||
_outParams.push_back(pt);
|
|
||||||
_blobs.insert(BLOBMap::value_type(pChar, const_cast<BLOB*>(&val)));
|
|
||||||
pVal = (SQLPOINTER) pChar;
|
|
||||||
}
|
|
||||||
else if (isInBound(dir))
|
|
||||||
{
|
|
||||||
pVal = (SQLPOINTER) val.rawContent();
|
|
||||||
ParamTuple pt((SQLPOINTER) pVal, size, SQL_C_BINARY, SQL_LONGVARBINARY);
|
|
||||||
_inParams.push_back(pt);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw IllegalStateException("Parameter must be [in] OR [out] bound.");
|
|
||||||
|
|
||||||
SQLLEN* pLenIn = new SQLLEN;
|
SQLLEN* pLenIn = new SQLLEN;
|
||||||
*pLenIn = size;
|
*pLenIn = size;
|
||||||
@@ -159,7 +140,7 @@ void Binder::bind(std::size_t pos, const Poco::Data::BLOB& val, Direction dir)
|
|||||||
|
|
||||||
if (Utility::isError(SQLBindParameter(_rStmt,
|
if (Utility::isError(SQLBindParameter(_rStmt,
|
||||||
(SQLUSMALLINT) pos + 1,
|
(SQLUSMALLINT) pos + 1,
|
||||||
getParamType(dir),
|
SQL_PARAM_INPUT,
|
||||||
SQL_C_BINARY,
|
SQL_C_BINARY,
|
||||||
SQL_LONGVARBINARY,
|
SQL_LONGVARBINARY,
|
||||||
(SQLUINTEGER) size,
|
(SQLUINTEGER) size,
|
||||||
@@ -216,15 +197,11 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
|
|||||||
|
|
||||||
std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
|
std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
|
||||||
{
|
{
|
||||||
ParamVec::const_iterator it = _inParams.begin();
|
ParamMap::const_iterator it = _inParams.find(pAddr);
|
||||||
ParamVec::const_iterator end = _inParams.end();
|
if (it != _inParams.end()) return it->second;
|
||||||
for (; it != end; ++it)
|
|
||||||
if (it->get<0>() == pAddr) return it->get<1>();
|
|
||||||
|
|
||||||
it = _outParams.begin();
|
it = _outParams.find(pAddr);
|
||||||
end = _outParams.end();
|
if (it != _outParams.end()) return it->second;
|
||||||
for (; it != end; ++it)
|
|
||||||
if (it->get<0>() == pAddr) return it->get<1>();
|
|
||||||
|
|
||||||
throw NotFoundException("Requested data size not found.");
|
throw NotFoundException("Requested data size not found.");
|
||||||
}
|
}
|
||||||
@@ -261,11 +238,6 @@ void Binder::synchronize()
|
|||||||
StringMap::iterator itStrEnd = _strings.end();
|
StringMap::iterator itStrEnd = _strings.end();
|
||||||
for(; itStr != itStrEnd; ++itStr)
|
for(; itStr != itStrEnd; ++itStr)
|
||||||
itStr->second->assign(itStr->first, strlen(itStr->first));
|
itStr->second->assign(itStr->first, strlen(itStr->first));
|
||||||
|
|
||||||
BLOBMap::iterator itB = _blobs.begin();
|
|
||||||
BLOBMap::iterator itBEnd = _blobs.end();
|
|
||||||
for(; itB != itBEnd; ++itB)
|
|
||||||
itB->second->assignRaw(itB->first, strlen(itB->first));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -191,8 +191,6 @@ void ODBCStatementImpl::bindImpl()
|
|||||||
if (SQL_NEED_DATA == rc) putData();
|
if (SQL_NEED_DATA == rc) putData();
|
||||||
else checkError(rc, "SQLExecute()");
|
else checkError(rc, "SQLExecute()");
|
||||||
|
|
||||||
getData();
|
|
||||||
|
|
||||||
_pBinder->synchronize();
|
_pBinder->synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,58 +198,23 @@ void ODBCStatementImpl::bindImpl()
|
|||||||
void ODBCStatementImpl::putData()
|
void ODBCStatementImpl::putData()
|
||||||
{
|
{
|
||||||
SQLPOINTER pParam = 0;
|
SQLPOINTER pParam = 0;
|
||||||
|
SQLINTEGER dataSize = 0;
|
||||||
SQLRETURN rc = SQLParamData(_stmt, &pParam);
|
SQLRETURN rc = SQLParamData(_stmt, &pParam);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
poco_assert_dbg (pParam);
|
poco_assert_dbg (pParam);
|
||||||
|
dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
|
||||||
SQLINTEGER dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
|
|
||||||
|
|
||||||
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
|
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
|
||||||
throw StatementException(_stmt, "SQLPutData()");
|
throw StatementException(_stmt, "SQLPutData()");
|
||||||
|
|
||||||
}while (SQL_NEED_DATA == (rc = SQLParamData(_stmt, &pParam)));
|
}while (SQL_NEED_DATA == (rc = SQLParamData(_stmt, &pParam)));
|
||||||
|
|
||||||
checkError(rc, "SQLParamData()");
|
checkError(rc, "SQLParamData()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ODBCStatementImpl::getData()
|
|
||||||
{
|
|
||||||
Binder::ParamVec& outParams = _pBinder->outParameters();
|
|
||||||
if (0 == outParams.size()) return;
|
|
||||||
|
|
||||||
Binder::ParamVec::iterator it = outParams.begin();
|
|
||||||
Binder::ParamVec::iterator end = outParams.end();
|
|
||||||
for (int i = 1; it != end; ++it, ++i)
|
|
||||||
{
|
|
||||||
SQLINTEGER retLen = 0;
|
|
||||||
char* ptr = (char*) it->get<0>();
|
|
||||||
SQLINTEGER len = it->get<1>();
|
|
||||||
//NB: Oracle SQLGetData call returns string data, but does NOT report the returned length.
|
|
||||||
// (no other drivers tested for this functionality yet)
|
|
||||||
// Thus, for the string length we trust ptr being zeroed when allocated in binder.
|
|
||||||
// As a "safety net", the last member of the binder-supplied char* array is set to '\0' (see below)
|
|
||||||
while (len > 0 && SQL_NO_DATA != (SQLGetData(_stmt, i, it->get<2>(), (SQLPOINTER) ptr, len, &retLen)))
|
|
||||||
{
|
|
||||||
if (0 == retLen ||
|
|
||||||
SQL_NULL_DATA == retLen ||
|
|
||||||
SQL_NO_TOTAL == retLen)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ptr + retLen < ptr + len)
|
|
||||||
{
|
|
||||||
ptr += retLen;
|
|
||||||
len -= retLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//just in case, terminate the string
|
|
||||||
((char*) it->get<0>())[it->get<1>()-1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ODBCStatementImpl::clear()
|
void ODBCStatementImpl::clear()
|
||||||
{
|
{
|
||||||
SQLRETURN rc = SQLCloseCursor(_stmt);
|
SQLRETURN rc = SQLCloseCursor(_stmt);
|
||||||
|
|||||||
@@ -926,7 +926,7 @@ void ODBCOracleTest::testStoredProcedure()
|
|||||||
k += 2;
|
k += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//string and BLOB for automatic binding only
|
//std::string automatic binding only
|
||||||
_pSession->setFeature("autoBind", true);
|
_pSession->setFeature("autoBind", true);
|
||||||
|
|
||||||
*_pSession << "CREATE OR REPLACE "
|
*_pSession << "CREATE OR REPLACE "
|
||||||
@@ -934,27 +934,20 @@ void ODBCOracleTest::testStoredProcedure()
|
|||||||
" BEGIN outParam := inParam; "
|
" BEGIN outParam := inParam; "
|
||||||
"END storedProcedure;" , now;
|
"END storedProcedure;" , now;
|
||||||
|
|
||||||
std::string inParam = "123";
|
std::string inParam =
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||||
|
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
std::string outParam;
|
std::string outParam;
|
||||||
try{
|
|
||||||
*_pSession << "{call storedProcedure(?,?)}", in(inParam), out(outParam), now;
|
*_pSession << "{call storedProcedure(?,?)}", in(inParam), out(outParam), now;
|
||||||
}catch(StatementException& ex){std::cout << ex.toString();}
|
|
||||||
assert(inParam == outParam);
|
assert(inParam == outParam);
|
||||||
dropObject("PROCEDURE", "storedProcedure");
|
dropObject("PROCEDURE", "storedProcedure");
|
||||||
/*TODO - currently failing
|
|
||||||
*_pSession << "CREATE OR REPLACE "
|
|
||||||
"PROCEDURE storedProcedure(inParam IN BLOB, outParam OUT BLOB) IS "
|
|
||||||
" BEGIN outParam := inParam; "
|
|
||||||
"END storedProcedure;" , now;
|
|
||||||
|
|
||||||
BLOB inBLOB = "123";
|
|
||||||
BLOB outBLOB;
|
|
||||||
try{
|
|
||||||
*_pSession << "{call storedProcedure(?,?)}", in(inBLOB), out(outBLOB), now;
|
|
||||||
}catch(StatementException& ex){std::cout << ex.toString();}
|
|
||||||
assert(inBLOB == outBLOB);
|
|
||||||
dropObject("PROCEDURE", "storedProcedure");
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -871,10 +871,10 @@ void ODBCSQLServerTest::testStoredProcedure()
|
|||||||
|
|
||||||
dropObject("PROCEDURE", "storedProcedure");
|
dropObject("PROCEDURE", "storedProcedure");
|
||||||
|
|
||||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
*_pSession << "CREATE PROCEDURE storedProcedure(@outParam int OUTPUT) AS "
|
||||||
"@outParam int OUTPUT "
|
"BEGIN "
|
||||||
"AS "
|
"SET @outParam = -1; "
|
||||||
"SET @outParam = -1 "
|
"END;"
|
||||||
, now;
|
, now;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -882,11 +882,10 @@ void ODBCSQLServerTest::testStoredProcedure()
|
|||||||
assert(-1 == i);
|
assert(-1 == i);
|
||||||
dropObject("PROCEDURE", "storedProcedure");
|
dropObject("PROCEDURE", "storedProcedure");
|
||||||
|
|
||||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
*_pSession << "CREATE PROCEDURE storedProcedure(@inParam int, @outParam int OUTPUT) AS "
|
||||||
"@inParam int, "
|
"BEGIN "
|
||||||
"@outParam int OUTPUT "
|
"SET @outParam = @inParam*@inParam; "
|
||||||
"AS "
|
"END;"
|
||||||
"SET @outParam = @inParam*@inParam "
|
|
||||||
, now;
|
, now;
|
||||||
|
|
||||||
i = 2;
|
i = 2;
|
||||||
@@ -895,10 +894,10 @@ void ODBCSQLServerTest::testStoredProcedure()
|
|||||||
assert(4 == j);
|
assert(4 == j);
|
||||||
dropObject("PROCEDURE", "storedProcedure");
|
dropObject("PROCEDURE", "storedProcedure");
|
||||||
|
|
||||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
*_pSession << "CREATE PROCEDURE storedProcedure(@ioParam int OUTPUT) AS "
|
||||||
"@ioParam int OUTPUT "
|
"BEGIN "
|
||||||
"AS "
|
"SET @ioParam = @ioParam*@ioParam; "
|
||||||
"SET @ioParam = @ioParam*@ioParam "
|
"END;"
|
||||||
, now;
|
, now;
|
||||||
|
|
||||||
i = 2;
|
i = 2;
|
||||||
@@ -908,6 +907,22 @@ void ODBCSQLServerTest::testStoredProcedure()
|
|||||||
|
|
||||||
k += 2;
|
k += 2;
|
||||||
}
|
}
|
||||||
|
/*TODO
|
||||||
|
_pSession->setFeature("autoBind", true);
|
||||||
|
*_pSession << "CREATE PROCEDURE storedProcedure(@inParam VARCHAR, @outParam VARCHAR OUTPUT) AS "
|
||||||
|
"BEGIN "
|
||||||
|
"SET @outParam = @inParam; "
|
||||||
|
"END;"
|
||||||
|
, now;
|
||||||
|
|
||||||
|
std::string inParam = "123";
|
||||||
|
std::string outParam;
|
||||||
|
try{
|
||||||
|
*_pSession << "{call storedProcedure(?, ?)}", in(inParam), out(outParam), now;
|
||||||
|
}catch(StatementException& ex){std::cout << ex.toString();}
|
||||||
|
assert(outParam == inParam);
|
||||||
|
dropObject("PROCEDURE", "storedProcedure");
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user