mirror of
https://github.com/pocoproject/poco.git
synced 2025-03-04 07:27:23 +01:00
This commit is contained in:
parent
649415d3b9
commit
8b374cd84b
@ -68,8 +68,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
|
||||
{
|
||||
public:
|
||||
typedef AbstractBinder::Direction Direction;
|
||||
typedef Tuple<SQLPOINTER, SQLLEN, SQLSMALLINT, SQLSMALLINT> ParamTuple;
|
||||
typedef std::vector<ParamTuple> ParamVec;
|
||||
typedef std::map<SQLPOINTER, SQLLEN> ParamMap;
|
||||
|
||||
static const size_t DEFAULT_PARAM_SIZE = 1024;
|
||||
|
||||
@ -145,14 +144,10 @@ public:
|
||||
/// Transfers the results of non-POD outbound parameters from internal
|
||||
/// holders back into the externally supplied buffers.
|
||||
|
||||
ParamVec& outParameters();
|
||||
/// Returns map of output parameter pointers and sizes.
|
||||
|
||||
private:
|
||||
typedef std::vector<SQLLEN*> LengthVec;
|
||||
typedef std::map<SQL_TIMESTAMP_STRUCT*, DateTime*> TimestampMap;
|
||||
typedef std::map<char*, std::string*> StringMap;
|
||||
typedef std::map<char*, BLOB*> BLOBMap;
|
||||
|
||||
void describeParameter(std::size_t pos);
|
||||
/// Sets the description field for the parameter, if needed.
|
||||
@ -204,12 +199,11 @@ private:
|
||||
|
||||
const StatementHandle& _rStmt;
|
||||
LengthVec _lengthIndicator;
|
||||
ParamVec _inParams;
|
||||
ParamVec _outParams;
|
||||
ParamMap _inParams;
|
||||
ParamMap _outParams;
|
||||
ParameterBinding _paramBinding;
|
||||
TimestampMap _timestamps;
|
||||
StringMap _strings;
|
||||
BLOBMap _blobs;
|
||||
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
|
||||
|
||||
|
||||
|
@ -71,10 +71,6 @@ Binder::~Binder()
|
||||
StringMap::iterator itStr = _strings.begin();
|
||||
StringMap::iterator itStrEnd = _strings.end();
|
||||
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))
|
||||
{
|
||||
Parameter p(_rStmt, pos);
|
||||
size = p.columnSize();
|
||||
size = (SQLINTEGER) p.columnSize();
|
||||
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;
|
||||
_outParams.insert(ParamMap::value_type(pVal, size));
|
||||
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
|
||||
}
|
||||
else if (isInBound(dir))
|
||||
{
|
||||
pVal = (SQLPOINTER) val.c_str();
|
||||
ParamTuple pt((SQLPOINTER) pVal, size, SQL_C_CHAR, SQL_LONGVARCHAR);
|
||||
_inParams.push_back(pt);
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
if (isOutBound(dir))
|
||||
{
|
||||
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.");
|
||||
_inParams.insert(ParamMap::value_type(pVal, size));
|
||||
|
||||
SQLLEN* pLenIn = new SQLLEN;
|
||||
*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,
|
||||
(SQLUSMALLINT) pos + 1,
|
||||
getParamType(dir),
|
||||
SQL_PARAM_INPUT,
|
||||
SQL_C_BINARY,
|
||||
SQL_LONGVARBINARY,
|
||||
(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
|
||||
{
|
||||
ParamVec::const_iterator it = _inParams.begin();
|
||||
ParamVec::const_iterator end = _inParams.end();
|
||||
for (; it != end; ++it)
|
||||
if (it->get<0>() == pAddr) return it->get<1>();
|
||||
ParamMap::const_iterator it = _inParams.find(pAddr);
|
||||
if (it != _inParams.end()) return it->second;
|
||||
|
||||
it = _outParams.begin();
|
||||
end = _outParams.end();
|
||||
for (; it != end; ++it)
|
||||
if (it->get<0>() == pAddr) return it->get<1>();
|
||||
it = _outParams.find(pAddr);
|
||||
if (it != _outParams.end()) return it->second;
|
||||
|
||||
throw NotFoundException("Requested data size not found.");
|
||||
}
|
||||
@ -261,11 +238,6 @@ void Binder::synchronize()
|
||||
StringMap::iterator itStrEnd = _strings.end();
|
||||
for(; itStr != itStrEnd; ++itStr)
|
||||
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();
|
||||
else checkError(rc, "SQLExecute()");
|
||||
|
||||
getData();
|
||||
|
||||
_pBinder->synchronize();
|
||||
}
|
||||
|
||||
@ -200,58 +198,23 @@ void ODBCStatementImpl::bindImpl()
|
||||
void ODBCStatementImpl::putData()
|
||||
{
|
||||
SQLPOINTER pParam = 0;
|
||||
SQLINTEGER dataSize = 0;
|
||||
SQLRETURN rc = SQLParamData(_stmt, &pParam);
|
||||
|
||||
do
|
||||
{
|
||||
poco_assert_dbg (pParam);
|
||||
dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
|
||||
|
||||
SQLINTEGER dataSize = (SQLINTEGER) _pBinder->parameterSize(pParam);
|
||||
|
||||
if (Utility::isError(SQLPutData(_stmt, pParam, dataSize)))
|
||||
throw StatementException(_stmt, "SQLPutData()");
|
||||
|
||||
}while (SQL_NEED_DATA == (rc = SQLParamData(_stmt, &pParam)));
|
||||
|
||||
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()
|
||||
{
|
||||
SQLRETURN rc = SQLCloseCursor(_stmt);
|
||||
@ -365,10 +328,10 @@ void ODBCStatementImpl::checkError(SQLRETURN rc, const std::string& msg)
|
||||
{
|
||||
if (Utility::isError(rc))
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << std::endl << "Requested SQL statement: " << toString() << std::endl;
|
||||
os << "Native SQL statement: " << nativeSQL() << std::endl;
|
||||
std::string str(msg); str += os.str();
|
||||
std::ostringstream os;
|
||||
os << std::endl << "Requested SQL statement: " << toString() << std::endl;
|
||||
os << "Native SQL statement: " << nativeSQL() << std::endl;
|
||||
std::string str(msg); str += os.str();
|
||||
|
||||
throw StatementException(_stmt, str);
|
||||
}
|
||||
|
@ -926,7 +926,7 @@ void ODBCOracleTest::testStoredProcedure()
|
||||
k += 2;
|
||||
}
|
||||
|
||||
//string and BLOB for automatic binding only
|
||||
//std::string automatic binding only
|
||||
_pSession->setFeature("autoBind", true);
|
||||
|
||||
*_pSession << "CREATE OR REPLACE "
|
||||
@ -934,27 +934,20 @@ void ODBCOracleTest::testStoredProcedure()
|
||||
" BEGIN outParam := inParam; "
|
||||
"END storedProcedure;" , now;
|
||||
|
||||
std::string inParam = "123";
|
||||
std::string inParam =
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||
std::string outParam;
|
||||
try{
|
||||
*_pSession << "{call storedProcedure(?,?)}", in(inParam), out(outParam), now;
|
||||
}catch(StatementException& ex){std::cout << ex.toString();}
|
||||
assert(inParam == outParam);
|
||||
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");
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
||||
"@outParam int OUTPUT "
|
||||
"AS "
|
||||
"SET @outParam = -1 "
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure(@outParam int OUTPUT) AS "
|
||||
"BEGIN "
|
||||
"SET @outParam = -1; "
|
||||
"END;"
|
||||
, now;
|
||||
|
||||
int i = 0;
|
||||
@ -882,11 +882,10 @@ void ODBCSQLServerTest::testStoredProcedure()
|
||||
assert(-1 == i);
|
||||
dropObject("PROCEDURE", "storedProcedure");
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
||||
"@inParam int, "
|
||||
"@outParam int OUTPUT "
|
||||
"AS "
|
||||
"SET @outParam = @inParam*@inParam "
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure(@inParam int, @outParam int OUTPUT) AS "
|
||||
"BEGIN "
|
||||
"SET @outParam = @inParam*@inParam; "
|
||||
"END;"
|
||||
, now;
|
||||
|
||||
i = 2;
|
||||
@ -895,10 +894,10 @@ void ODBCSQLServerTest::testStoredProcedure()
|
||||
assert(4 == j);
|
||||
dropObject("PROCEDURE", "storedProcedure");
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure "
|
||||
"@ioParam int OUTPUT "
|
||||
"AS "
|
||||
"SET @ioParam = @ioParam*@ioParam "
|
||||
*_pSession << "CREATE PROCEDURE storedProcedure(@ioParam int OUTPUT) AS "
|
||||
"BEGIN "
|
||||
"SET @ioParam = @ioParam*@ioParam; "
|
||||
"END;"
|
||||
, now;
|
||||
|
||||
i = 2;
|
||||
@ -908,6 +907,22 @@ void ODBCSQLServerTest::testStoredProcedure()
|
||||
|
||||
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");
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -920,11 +935,11 @@ void ODBCSQLServerTest::testStoredFunction()
|
||||
|
||||
dropObject("PROCEDURE", "storedFunction");
|
||||
*_pSession << "CREATE PROCEDURE storedFunction AS "
|
||||
"BEGIN "
|
||||
"DECLARE @retVal int;"
|
||||
"SET @retVal = -1;"
|
||||
"RETURN @retVal;"
|
||||
"END;"
|
||||
"BEGIN "
|
||||
"DECLARE @retVal int;"
|
||||
"SET @retVal = -1;"
|
||||
"RETURN @retVal;"
|
||||
"END;"
|
||||
, now;
|
||||
|
||||
int i = 0;
|
||||
@ -934,9 +949,9 @@ void ODBCSQLServerTest::testStoredFunction()
|
||||
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedFunction(@inParam int) AS "
|
||||
"BEGIN "
|
||||
"RETURN @inParam*@inParam;"
|
||||
"END;"
|
||||
"BEGIN "
|
||||
"RETURN @inParam*@inParam;"
|
||||
"END;"
|
||||
, now;
|
||||
|
||||
i = 2;
|
||||
@ -947,10 +962,10 @@ void ODBCSQLServerTest::testStoredFunction()
|
||||
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedFunction(@inParam int, @outParam int OUTPUT) AS "
|
||||
"BEGIN "
|
||||
"SET @outParam = @inParam*@inParam;"
|
||||
"RETURN @outParam;"
|
||||
"END"
|
||||
"BEGIN "
|
||||
"SET @outParam = @inParam*@inParam;"
|
||||
"RETURN @outParam;"
|
||||
"END"
|
||||
, now;
|
||||
|
||||
i = 2;
|
||||
@ -963,13 +978,13 @@ void ODBCSQLServerTest::testStoredFunction()
|
||||
|
||||
|
||||
*_pSession << "CREATE PROCEDURE storedFunction(@param1 int OUTPUT,@param2 int OUTPUT) AS "
|
||||
"BEGIN "
|
||||
"DECLARE @temp int; "
|
||||
"SET @temp = @param1;"
|
||||
"SET @param1 = @param2;"
|
||||
"SET @param2 = @temp;"
|
||||
"RETURN @param1 + @param2; "
|
||||
"END"
|
||||
"BEGIN "
|
||||
"DECLARE @temp int; "
|
||||
"SET @temp = @param1;"
|
||||
"SET @param1 = @param2;"
|
||||
"SET @param2 = @temp;"
|
||||
"RETURN @param1 + @param2; "
|
||||
"END"
|
||||
, now;
|
||||
|
||||
i = 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user