From 6a5afde278b81009a3e532b4ff602f7b4f4f943d Mon Sep 17 00:00:00 2001 From: Aleksandar Fabijanic Date: Tue, 19 Jun 2007 02:13:30 +0000 Subject: [PATCH] stored procedure and gcc fixes --- Data/ODBC/include/Poco/Data/ODBC/Binder.h | 26 +++++++++++-- Data/ODBC/src/Binder.cpp | 17 ++++---- Data/ODBC/src/ODBCStatementImpl.cpp | 2 +- Data/ODBC/testsuite/src/ODBCMySQLTest.cpp | 10 +++++ Data/ODBC/testsuite/src/ODBCOracleTest.cpp | 6 +-- .../ODBC/testsuite/src/ODBCPostgreSQLTest.cpp | 39 ++++++++++++------- Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp | 12 ++++++ Data/include/Poco/Data/StatementImpl.h | 4 +- 8 files changed, 86 insertions(+), 30 deletions(-) diff --git a/Data/ODBC/include/Poco/Data/ODBC/Binder.h b/Data/ODBC/include/Poco/Data/ODBC/Binder.h index d8696615e..9ce7c34ae 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Binder.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Binder.h @@ -168,13 +168,33 @@ private: SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; - if (_pTypeInfo) + try { - try + // This is a proper way to find out about database specific type sizes. + // Not all drivers are equally willing to cooperate in this matter, though. + // Hence the funky flow control. + if (_pTypeInfo) { colSize = _pTypeInfo->getInfo(cDataType, "COLUMN_SIZE"); decDigits = _pTypeInfo->getInfo(cDataType, "MINIMUM_SCALE"); - }catch (NotFoundException&) { } + } + else throw NotFoundException(); + }catch (NotFoundException&) + { + try + { + Parameter p(_rStmt, pos); + colSize = (SQLINTEGER) p.columnSize(); + decDigits = (SQLSMALLINT) p.decimalDigits(); + }catch (StatementException&) + { + try + { + ODBCColumn c(_rStmt, pos); + colSize = (SQLINTEGER) c.length(); + decDigits = (SQLSMALLINT) c.precision(); + }catch (StatementException&) { } + } } if (Utility::isError(SQLBindParameter(_rStmt, diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp index e6c73d2a1..03dc13737 100644 --- a/Data/ODBC/src/Binder.cpp +++ b/Data/ODBC/src/Binder.cpp @@ -87,18 +87,21 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir) size = (SQLUINTEGER) p.columnSize(); } catch (StatementException&) - // some drivers (e.g. MS SQL) refuse to describe output parameters { + size = DEFAULT_PARAM_SIZE; +//On Linux, PostgreSQL driver segfaults on SQLGetDescField, so this is disabled for now +#ifdef POCO_OS_FAMILY_WINDOWS SQLHDESC hIPD = 0; if (!Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_IMP_PARAM_DESC, &hIPD, 0, 0))) { - size = 1024; - SQLUINTEGER sz = size; - if (Utility::isError(SQLSetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, 0))) - throw StatementException(_rStmt, "Could not set output parameter size"); + SQLUINTEGER sz = 0; + if (!Utility::isError(SQLGetDescField(hIPD, (SQLSMALLINT) pos + 1, SQL_DESC_LENGTH, &sz, sizeof(sz), 0)) && + sz > 0) + { + size = sz; + } } - else - throw StatementException(_rStmt, "Could not get statement IPD attribute handle."); +#endif } char* pChar = (char*) std::calloc(size, sizeof(char)); diff --git a/Data/ODBC/src/ODBCStatementImpl.cpp b/Data/ODBC/src/ODBCStatementImpl.cpp index 32321fe9e..087774894 100644 --- a/Data/ODBC/src/ODBCStatementImpl.cpp +++ b/Data/ODBC/src/ODBCStatementImpl.cpp @@ -118,7 +118,7 @@ void ODBCStatementImpl::compileImpl() _pBinder = new Binder(_stmt, bind, pDT); _pExtractor = new Extractor(_stmt, *_pPreparation); - + // This is a hack to conform to some ODBC drivers behavior (e.g. MS SQLServer) with // stored procedure calls: driver refuses to report the number of columns, unless all // parameters for the stored procedure are bound. Since number of columns is essential diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp index f7f69a25e..33f820adc 100644 --- a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp @@ -868,6 +868,11 @@ void ODBCMySQLTest::testStoredProcedure() //MySQL is currently buggy in this area: // http://bugs.mysql.com/bug.php?id=17898 // http://bugs.mysql.com/bug.php?id=27632 + // Additionally, the standard ODBC stored procedure call syntax + // {call storedProcedure(?)} is currently (3.51.12.00) not supported. + // See http://bugs.mysql.com/bug.php?id=26535 + // Poco::Data support for MySQL ODBC is postponed until the above + // issues are resolved. } @@ -876,6 +881,11 @@ void ODBCMySQLTest::testStoredFunction() //MySQL is currently buggy in this area: // http://bugs.mysql.com/bug.php?id=17898 // http://bugs.mysql.com/bug.php?id=27632 + // Additionally, the standard ODBC stored procedure call syntax + // {call storedProcedure(?)} is currently (3.51.12.00) not supported. + // See http://bugs.mysql.com/bug.php?id=26535 + // Poco::Data support for MySQL ODBC is postponed until the above + // issues are resolved. } diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp index 649fdd61d..0553fab16 100644 --- a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp @@ -926,7 +926,8 @@ void ODBCOracleTest::testStoredProcedure() k += 2; } - //std::string automatic binding only + + //strings only work with auto-binding _pSession->setFeature("autoBind", true); *_pSession << "CREATE OR REPLACE " @@ -1019,11 +1020,10 @@ void ODBCOracleTest::testStoredFunction() assert(2 == params.get<0>()); assert(3 == result); dropObject("FUNCTION", "storedFunction"); - + k += 2; } - //string for automatic binding only _pSession->setFeature("autoBind", true); *_pSession << "CREATE OR REPLACE " diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp index 5b9edf9ef..2f15f2323 100644 --- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp @@ -36,6 +36,7 @@ #include "Poco/String.h" #include "Poco/Format.h" #include "Poco/Tuple.h" +#include "Poco/DateTime.h" #include "Poco/Exception.h" #include "Poco/Data/Common.h" #include "Poco/Data/BLOB.h" @@ -57,6 +58,7 @@ using Poco::Data::ODBC::StatementException; using Poco::Data::ODBC::StatementDiagnostics; using Poco::format; using Poco::Tuple; +using Poco::DateTime; using Poco::NotFoundException; @@ -894,21 +896,32 @@ void ODBCPostgreSQLTest::testStoredFunction() *_pSession << "{? = call storedFunction(?)}", out(result), in(i), now; assert(4 == result); dropObject("FUNCTION", "storedFunction(INTEGER)"); -/*TODO - *_pSession << "CREATE FUNCTION storedFunction(TEXT) RETURNS TEXT AS '" - "BEGIN " - " RETURN $1;" - "END;'" - "LANGUAGE 'plpgsql'" , now; + + + *_pSession << "CREATE FUNCTION storedFunction(TIMESTAMP) RETURNS TIMESTAMP AS '" + "BEGIN " + " RETURN $1; " + "END;'" + "LANGUAGE 'plpgsql'" , now; + + DateTime dtIn(1965, 6, 18, 5, 35, 1); + DateTime dtOut; + *_pSession << "{? = call storedFunction(?)}", out(dtOut), in(dtIn), now; + assert(dtOut == dtIn); + dropObject("FUNCTION", "storedFunction(TIMESTAMP)"); + + *_pSession << "CREATE FUNCTION storedFunction(TEXT,TEXT) RETURNS TEXT AS '" + "BEGIN " + " RETURN $1 || '', '' || $2 || ''!'';" + "END;'" + "LANGUAGE 'plpgsql'" , now; - std::string param = "123"; + std::string param1 = "Hello"; + std::string param2 = "world"; std::string ret; - try { - *_pSession << "{? = call storedFunction(?)}", out(ret), in(param), now; - }catch(StatementException & ex) { std::cout << ex.toString();} - assert(ret == param); - dropObject("FUNCTION", "storedFunction(TEXT)"); -*/ + *_pSession << "{? = call storedFunction(?,?)}", out(ret), in(param1), in(param2), now; + assert(ret == "Hello, world!"); + dropObject("FUNCTION", "storedFunction(TEXT, TEXT)"); k += 2; } diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index d9612536d..adffdd4a0 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -36,6 +36,7 @@ #include "Poco/String.h" #include "Poco/Format.h" #include "Poco/Tuple.h" +#include "Poco/DateTime.h" #include "Poco/Exception.h" #include "Poco/Data/Common.h" #include "Poco/Data/BLOB.h" @@ -56,6 +57,7 @@ using Poco::Data::ODBC::StatementException; using Poco::Data::ODBC::StatementDiagnostics; using Poco::format; using Poco::Tuple; +using Poco::DateTime; using Poco::NotFoundException; @@ -905,6 +907,16 @@ void ODBCSQLServerTest::testStoredProcedure() assert(4 == i); dropObject("PROCEDURE", "storedProcedure"); + *_pSession << "CREATE PROCEDURE storedProcedure(@ioParam DATETIME OUTPUT) AS " + "BEGIN " + " SET @ioParam = @ioParam + 1; " + "END;" , now; + + DateTime dt(1965, 6, 18, 5, 35, 1); + *_pSession << "{call storedProcedure(?)}", io(dt), now; + assert(19 == dt.day()); + dropObject("PROCEDURE", "storedProcedure"); + k += 2; } /*TODO - currently fails with following error: diff --git a/Data/include/Poco/Data/StatementImpl.h b/Data/include/Poco/Data/StatementImpl.h index c24813360..e70b1d0fe 100644 --- a/Data/include/Poco/Data/StatementImpl.h +++ b/Data/include/Poco/Data/StatementImpl.h @@ -46,6 +46,7 @@ #include "Poco/Data/Range.h" #include "Poco/Data/Column.h" #include "Poco/Data/Extraction.h" +#include "Poco/Data/SessionImpl.h" #include "Poco/RefCountedObject.h" #include "Poco/AutoPtr.h" #include "Poco/String.h" @@ -61,9 +62,6 @@ namespace Poco { namespace Data { -class SessionImpl; - - class Data_API StatementImpl: public Poco::RefCountedObject /// StatementImpl interface that subclasses must implement to define database dependent query execution. ///