mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 10:13:51 +01:00
4368 fix oracle failing odbc tests (#4611)
* chore(CI): enable oracle ODBC tests #4368 * fix(ODBC): Oracle AutoTransaction test case; add explicit ODBC exceptions instantiation #4368 * fix(odbc): oracle test table creation error detection #4368 * enh(Data): enforce sql parsing for transaction tests to avoid select-only transactions #4368 --------- Co-authored-by: cunj123 <n.belusic@pta.hr>
This commit is contained in:
parent
a6762f51cf
commit
7064ae3c2d
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -700,12 +700,12 @@ jobs:
|
||||
# POSTGRES_PASSWORD: postgres
|
||||
# ports:
|
||||
# - 5432:5432
|
||||
#oracle:
|
||||
# image: container-registry.oracle.com/database/express:21.3.0-xe
|
||||
# env:
|
||||
# ORACLE_PWD: poco
|
||||
# ports:
|
||||
# - 1521:1521
|
||||
oracle:
|
||||
image: container-registry.oracle.com/database/express:21.3.0-xe
|
||||
env:
|
||||
ORACLE_PWD: poco
|
||||
ports:
|
||||
- 1521:1521
|
||||
sqlserver:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
env:
|
||||
@ -716,25 +716,17 @@ jobs:
|
||||
- 1433:1433
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev alien libaio1 gnupg2 curl # libmysqlclient-dev mysql-client odbc-postgresql
|
||||
- run: sudo apt -y update && sudo apt -y install libssl-dev unixodbc-dev alien libaio1 gnupg2 curl odbcinst1debian2 libodbc1 odbcinst # libmysqlclient-dev mysql-client odbc-postgresql
|
||||
- run: ./configure --everything --no-samples --omit=ActiveRecord,ApacheConnector,CppParser,Crypto,Data/MySQL,Data/PostgreSQL,Data/SQLite,Encodings,JSON,JWT,MongoDB,Net,NetSSL_OpenSSL,NetSSL_Win,PDF,PageCompiler,PocoDoc,ProGen,Prometheus,Redis,SevenZip,Util,XML,Zip && make all -s -j4 && sudo make install
|
||||
# - name: Setup MySQL ODBC connector
|
||||
# run: |
|
||||
# wget https://dev.mysql.com/get/Downloads/Connector-ODBC/8.2/mysql-connector-odbc_8.2.0-1ubuntu22.04_amd64.deb
|
||||
# wget https://dev.mysql.com/get/Downloads/MySQL-8.2/mysql-community-client-plugins_8.2.0-1ubuntu22.04_amd64.deb
|
||||
# sudo dpkg -i mysql-community-client-plugins_8.2.0-1ubuntu22.04_amd64.deb mysql-connector-odbc_8.2.0-1ubuntu22.04_amd64.deb
|
||||
# - name: Setup Oracle ODBC connector
|
||||
# run: |
|
||||
# wget https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-basic-21.12.0.0.0-1.x86_64.rpm
|
||||
# wget https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-sqlplus-21.12.0.0.0-1.x86_64.rpm
|
||||
# wget https://download.oracle.com/otn_software/linux/instantclient/2112000/oracle-instantclient-odbc-21.12.0.0.0-1.x86_64.rpm
|
||||
# sudo alien --scripts ./oracle-instantclient-basic-21.12.0.0.0-1.x86_64.rpm
|
||||
# sudo alien --scripts ./oracle-instantclient-sqlplus-21.12.0.0.0-1.x86_64.rpm
|
||||
# sudo alien --scripts ./oracle-instantclient-odbc-21.12.0.0.0-1.x86_64.rpm
|
||||
# sudo apt install ./oracle-instantclient-basic_21.12.0.0.0-2_amd64.deb
|
||||
# sudo apt install ./oracle-instantclient-sqlplus_21.12.0.0.0-2_amd64.deb
|
||||
# sudo apt install ./oracle-instantclient-odbc_21.12.0.0.0-2_amd64.deb
|
||||
# sudo /usr/lib/oracle/21/client64/bin/odbc_update_ini.sh / "/usr/lib/oracle/21/client64/lib" "" "" "/etc/odbc.ini"
|
||||
- name: Setup Oracle ODBC connector
|
||||
run: |
|
||||
wget https://www.devart.com/odbc/oracle/devartodbcoracle_amd64.deb
|
||||
sudo dpkg -i devartodbcoracle_amd64.deb
|
||||
- name: Setup SQL Server ODBC connector
|
||||
run: |
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
|
||||
|
@ -3857,6 +3857,8 @@ void SQLExecutor::sessionTransaction(const std::string& connector, const std::st
|
||||
}
|
||||
|
||||
bool autoCommit = session().getFeature("autoCommit");
|
||||
bool sqlParse = session().getFeature("sqlParse");
|
||||
session().setFeature("sqlParse", true);
|
||||
|
||||
Session local(connector, connect);
|
||||
|
||||
@ -3925,6 +3927,7 @@ void SQLExecutor::sessionTransaction(const std::string& connector, const std::st
|
||||
// end autoCommit = true
|
||||
|
||||
// restore the original transaction state
|
||||
session().setFeature("sqlParse", sqlParse);
|
||||
session().setFeature("autoCommit", autoCommit);
|
||||
}
|
||||
|
||||
@ -3932,6 +3935,8 @@ void SQLExecutor::sessionTransaction(const std::string& connector, const std::st
|
||||
void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, const std::string& connect)
|
||||
{
|
||||
bool autoCommit = session().getFeature("autoCommit");
|
||||
bool sqlParse = session().getFeature("sqlParse");
|
||||
session().setFeature("sqlParse", true);
|
||||
|
||||
Session local(connector, connect);
|
||||
local.setFeature("autoCommit", false);
|
||||
@ -4019,6 +4024,8 @@ void SQLExecutor::sessionTransactionNoAutoCommit(const std::string& connector, c
|
||||
session().commit();
|
||||
local.commit();
|
||||
#endif
|
||||
|
||||
session().setFeature("sqlParse", sqlParse);
|
||||
session().setFeature("autoCommit", autoCommit);
|
||||
}
|
||||
|
||||
@ -4033,9 +4040,12 @@ void SQLExecutor::transaction(const std::string& connector, const std::string& c
|
||||
|
||||
Session local(connector, connect);
|
||||
local.setFeature("autoCommit", true);
|
||||
local.setFeature("sqlParse", true);
|
||||
|
||||
bool autoCommit = session().getFeature("autoCommit");
|
||||
auto ti = session().getTransactionIsolation();
|
||||
bool sqlParse = session().getFeature("sqlParse");
|
||||
session().setFeature("sqlParse", true);
|
||||
|
||||
setTransactionIsolation(session(), Session::TRANSACTION_READ_COMMITTED);
|
||||
if (local.hasTransactionIsolation(Session::TRANSACTION_READ_UNCOMMITTED))
|
||||
@ -4157,6 +4167,7 @@ void SQLExecutor::transaction(const std::string& connector, const std::string& c
|
||||
session().commit();
|
||||
|
||||
// restore the original transaction state
|
||||
session().setFeature("sqlParse", sqlParse);
|
||||
session().setFeature("autoCommit", autoCommit);
|
||||
setTransactionIsolation(session(), ti);
|
||||
}
|
||||
@ -4192,6 +4203,8 @@ void SQLExecutor::transactor()
|
||||
|
||||
session().setFeature("autoCommit", false);
|
||||
session().setTransactionIsolation(Session::TRANSACTION_READ_COMMITTED);
|
||||
bool sqlParse = session().getFeature("sqlParse");
|
||||
session().setFeature("sqlParse", true);
|
||||
|
||||
TestCommitTransactor ct;
|
||||
Transaction t1(session(), ct);
|
||||
@ -4249,6 +4262,7 @@ void SQLExecutor::transactor()
|
||||
session().commit();
|
||||
|
||||
// restore the original transaction state
|
||||
session().setFeature("sqlParse", sqlParse);
|
||||
session().setFeature("autoCommit", autoCommit);
|
||||
setTransactionIsolation(session(), ti);
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ namespace Data {
|
||||
namespace ODBC {
|
||||
|
||||
|
||||
template <typename H, SQLSMALLINT handleType>
|
||||
class Error;
|
||||
|
||||
|
||||
template <typename H, SQLSMALLINT handleType>
|
||||
class Diagnostics
|
||||
/// Utility class providing functionality for retrieving ODBC diagnostic
|
||||
@ -213,6 +217,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
const H& handle() const
|
||||
{
|
||||
return _handle;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Diagnostics();
|
||||
@ -226,13 +236,22 @@ private:
|
||||
|
||||
/// Context handle
|
||||
const H& _handle;
|
||||
|
||||
friend class Error<H, handleType>;
|
||||
};
|
||||
|
||||
|
||||
typedef Diagnostics<SQLHENV, SQL_HANDLE_ENV> EnvironmentDiagnostics;
|
||||
typedef Diagnostics<SQLHDBC, SQL_HANDLE_DBC> ConnectionDiagnostics;
|
||||
typedef Diagnostics<SQLHSTMT, SQL_HANDLE_STMT> StatementDiagnostics;
|
||||
typedef Diagnostics<SQLHDESC, SQL_HANDLE_DESC> DescriptorDiagnostics;
|
||||
// explicit instantiation definition
|
||||
template class Diagnostics<SQLHENV, SQL_HANDLE_ENV>;
|
||||
template class Diagnostics<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
template class Diagnostics<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
template class Diagnostics<SQLHDESC, SQL_HANDLE_DESC>;
|
||||
|
||||
|
||||
using EnvironmentDiagnostics = Diagnostics<SQLHENV, SQL_HANDLE_ENV>;
|
||||
using ConnectionDiagnostics = Diagnostics<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
using StatementDiagnostics = Diagnostics<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
using DescriptorDiagnostics = Diagnostics<SQLHDESC, SQL_HANDLE_DESC>;
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
|
@ -41,26 +41,38 @@ class Error
|
||||
/// as well as individual diagnostic records.
|
||||
{
|
||||
public:
|
||||
explicit Error(const H& handle) : _diagnostics(handle)
|
||||
explicit Error(const H& handle) : _pDiag(new Diagnostics<H, handleType>(handle))
|
||||
/// Creates the Error.
|
||||
{
|
||||
}
|
||||
|
||||
Error(const Error& other) : Error(other.diagnostics().handle())
|
||||
/// Creates the Error from another one.
|
||||
{
|
||||
}
|
||||
|
||||
~Error()
|
||||
/// Destroys the Error.
|
||||
{
|
||||
}
|
||||
|
||||
Error& operator = (const Error& other)
|
||||
/// Assigns another Error to this one.
|
||||
{
|
||||
_pDiag.reset(new Diagnostics<H, handleType>(other.diagnostics().handle()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Diagnostics<H, handleType>& diagnostics() const
|
||||
/// Returns the associated diagnostics.
|
||||
{
|
||||
return _diagnostics;
|
||||
return *_pDiag;
|
||||
}
|
||||
|
||||
int count() const
|
||||
/// Returns the count of diagnostic records.
|
||||
{
|
||||
return (int) _diagnostics.count();
|
||||
return (int) _pDiag->count();
|
||||
}
|
||||
|
||||
std::string& toString(int index, std::string& str) const
|
||||
@ -76,9 +88,9 @@ public:
|
||||
"===========================\n"
|
||||
"SQLSTATE = %s\nNative Error Code = %ld\n%s\n\n",
|
||||
index + 1,
|
||||
_diagnostics.sqlState(index),
|
||||
_diagnostics.nativeError(index),
|
||||
_diagnostics.message(index));
|
||||
_pDiag->sqlState(index),
|
||||
_pDiag->nativeError(index),
|
||||
_pDiag->message(index));
|
||||
|
||||
str.append(s);
|
||||
|
||||
@ -92,8 +104,8 @@ public:
|
||||
|
||||
Poco::format(str,
|
||||
"Connection:%s\nServer:%s\n",
|
||||
_diagnostics.connectionName(),
|
||||
_diagnostics.serverName());
|
||||
_pDiag->connectionName(),
|
||||
_pDiag->serverName());
|
||||
|
||||
std::string s;
|
||||
for (int i = 0; i < count(); ++i)
|
||||
@ -108,14 +120,21 @@ public:
|
||||
private:
|
||||
Error();
|
||||
|
||||
Diagnostics<H, handleType> _diagnostics;
|
||||
std::unique_ptr<Diagnostics<H, handleType>> _pDiag;
|
||||
};
|
||||
|
||||
|
||||
typedef Error<SQLHENV, SQL_HANDLE_ENV> EnvironmentError;
|
||||
typedef Error<SQLHDBC, SQL_HANDLE_DBC> ConnectionError;
|
||||
typedef Error<SQLHSTMT, SQL_HANDLE_STMT> StatementError;
|
||||
typedef Error<SQLHSTMT, SQL_HANDLE_DESC> DescriptorError;
|
||||
// explicit instantiation definition
|
||||
template class Error<SQLHENV, SQL_HANDLE_ENV>;
|
||||
template class Error<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
template class Error<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
template class Error<SQLHDESC, SQL_HANDLE_DESC>;
|
||||
|
||||
|
||||
using EnvironmentError = Error<SQLHENV, SQL_HANDLE_ENV>;
|
||||
using ConnectionError = Error<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
using StatementError = Error<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
using DescriptorError = Error<SQLHSTMT, SQL_HANDLE_DESC>;
|
||||
|
||||
|
||||
} } } // namespace Poco::Data::ODBC
|
||||
|
@ -138,6 +138,13 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// explicit instantiation definition
|
||||
template class HandleException<SQLHENV, SQL_HANDLE_ENV>;
|
||||
template class HandleException<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
template class HandleException<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
template class HandleException<SQLHDESC, SQL_HANDLE_DESC>;
|
||||
|
||||
|
||||
using EnvironmentException = HandleException<SQLHENV, SQL_HANDLE_ENV>;
|
||||
using ConnectionException = HandleException<SQLHDBC, SQL_HANDLE_DBC>;
|
||||
using StatementException = HandleException<SQLHSTMT, SQL_HANDLE_STMT>;
|
||||
|
@ -50,6 +50,9 @@ public:
|
||||
~ODBCStatementImpl();
|
||||
/// Destroys the ODBCStatementImpl.
|
||||
|
||||
std::string nativeSQL();
|
||||
/// Returns the SQL string as modified by the driver.
|
||||
|
||||
protected:
|
||||
std::size_t columnsReturned() const;
|
||||
/// Returns number of columns returned by query.
|
||||
@ -91,9 +94,6 @@ protected:
|
||||
void execDirectImpl(const std::string& query);
|
||||
/// Execute query directly impl
|
||||
|
||||
std::string nativeSQL();
|
||||
/// Returns the SQL string as modified by the driver.
|
||||
|
||||
void printErrors(std::ostream& os) const;
|
||||
/// Print errors, if any.
|
||||
|
||||
|
@ -649,6 +649,10 @@ void ODBCOracleTest::testAutoTransaction()
|
||||
Session localSession("ODBC", _connectString);
|
||||
bool ac = session().getFeature("autoCommit");
|
||||
int count = 0;
|
||||
// enabing SQL parsing is necessary to prevent
|
||||
// starting a transaction for a simple select
|
||||
bool sqlParse = session().getFeature("sqlParse");
|
||||
session().setFeature("sqlParse", true);
|
||||
|
||||
recreateIntsTable();
|
||||
|
||||
@ -675,10 +679,19 @@ void ODBCOracleTest::testAutoTransaction()
|
||||
session() << "INSERT INTO Strings VALUES (1)", now;
|
||||
session() << "INSERT INTO Strings VALUES (2)", now;
|
||||
session() << "BAD QUERY", now;
|
||||
} catch (Poco::Exception&) {}
|
||||
failmsg("Bad SQL statement must throw");
|
||||
}
|
||||
catch (Poco::Exception&) {}
|
||||
|
||||
assertFalse (session().isTransaction());
|
||||
|
||||
session() << "SELECT count(*) FROM Strings", into(count), now;
|
||||
assertTrue (0 == count);
|
||||
assertFalse (session().isTransaction());
|
||||
|
||||
session() << "SELECT count(*) FROM Strings", into(count), now;
|
||||
assertTrue (0 == count);
|
||||
assertFalse (session().isTransaction());
|
||||
|
||||
AutoTransaction at(session());
|
||||
|
||||
@ -694,6 +707,7 @@ void ODBCOracleTest::testAutoTransaction()
|
||||
localSession << "SELECT count(*) FROM Strings", into(count), now;
|
||||
assertTrue (3 == count);
|
||||
|
||||
session().setFeature("sqlParse", sqlParse);
|
||||
session().setFeature("autoCommit", ac);
|
||||
}
|
||||
|
||||
@ -711,8 +725,9 @@ void ODBCOracleTest::dropObject(const std::string& type, const std::string& name
|
||||
StatementDiagnostics::Iterator it = flds.begin();
|
||||
for (; it != flds.end(); ++it)
|
||||
{
|
||||
if (4043 == it->_nativeError || //ORA-04043 (object does not exist)
|
||||
942 == it->_nativeError || 1433808584/*DevArt*/== it->_nativeError) //ORA-00942 (table does not exist)
|
||||
std::string errMsg((char*)it->_message);
|
||||
if ((errMsg.find("ORA-00942") != std::string::npos) || // table does not exist
|
||||
(errMsg.find("ORA-04043") != std::string::npos)) // object does not exist
|
||||
{
|
||||
ignoreError = true;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user