This commit is contained in:
Aleksandar Fabijanic 2007-06-08 01:33:56 +00:00
parent 649415d3b9
commit 8b374cd84b
5 changed files with 82 additions and 163 deletions

View File

@ -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

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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");
*/
}

View File

@ -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;