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:
Aleksandar Fabijanic 2024-07-24 06:05:08 -05:00 committed by GitHub
parent a6762f51cf
commit 7064ae3c2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 108 additions and 42 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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