feat(Data::Session): add 'sqlParse' feature #4230

This commit is contained in:
Alex Fabijanic 2023-11-02 00:04:10 +01:00
parent 79e54d88ba
commit afd9c8c408
7 changed files with 97 additions and 16 deletions

View File

@ -55,7 +55,8 @@ public:
_storage(std::string("deque")),
_bulk(false),
_emptyStringIsNull(false),
_forceEmptyString(false)
_forceEmptyString(false),
_sqlParse(true)
/// Creates the AbstractSessionImpl.
///
/// Adds "storage" property and sets the default internal storage container
@ -108,6 +109,10 @@ public:
addFeature("forceEmptyString",
&AbstractSessionImpl<C>::setForceEmptyString,
&AbstractSessionImpl<C>::getForceEmptyString);
addFeature("sqlParse",
&AbstractSessionImpl<C>::setSQLParse,
&AbstractSessionImpl<C>::getSQLParse);
}
~AbstractSessionImpl()
@ -257,7 +262,7 @@ public:
return _emptyStringIsNull;
}
void setForceEmptyString(const std::string& name, bool forceEmptyString)
void setForceEmptyString(const std::string&, bool forceEmptyString)
/// Sets the behavior regarding empty variable length strings.
/// Those are treated as NULL by Oracle and as empty string by
/// most other databases.
@ -278,6 +283,25 @@ public:
return _forceEmptyString;
}
void setSQLParse(const std::string&, bool doParse)
/// Enables the SQL parsing. Value must be of type bool.
/// When SQL parsing is enabled (default), the Statement attempts
/// to parse the SQL prior to executing it. The parsing is done
/// in non-autocommit mode only, with purpose to determine the
/// type of query and whether to start the transaction automatically.
///
/// See Statement documentation for more information.
{
_sqlParse = doParse;
}
bool getSQLParse(const std::string& name = "") const
/// Returns the value of the SQL parsing flag.
{
return _sqlParse;
}
protected:
void addFeature(const std::string& name, FeatureSetter setter, FeatureGetter getter)
/// Adds a feature to the map of supported features.
@ -325,6 +349,7 @@ private:
bool _bulk;
bool _emptyStringIsNull;
bool _forceEmptyString;
bool _sqlParse;
Poco::Any _handle;
};

View File

@ -118,7 +118,7 @@ public:
/// Returns true if session has transaction capabilities.
virtual bool isTransaction() const = 0;
/// Returns true iff a transaction is a transaction is in progress, false otherwise.
/// Returns true iff a transaction is in progress, false otherwise.
virtual void setTransactionIsolation(Poco::UInt32) = 0;
/// Sets the transaction isolation level.
@ -149,6 +149,9 @@ public:
bool isAutocommit() const;
/// Returns true if autocommit is on, false otherwise.
bool shouldParse() const;
/// Returns true if SQL parser is enabled, false otherwise.
virtual bool hasFeature(const std::string& name) const = 0;
/// Returns true if session has the named feature.
@ -247,6 +250,12 @@ inline bool SessionImpl::isAutocommit() const
}
inline bool SessionImpl::shouldParse() const
{
return hasFeature("sqlParse") && getFeature("sqlParse");
}
} } // namespace Poco::Data

View File

@ -578,7 +578,9 @@ inline const std::string& Statement::parseError()
inline Optional<bool> Statement::isSelect() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return isType(Parser::StatementType::kStmtSelect);
if (_pImpl->session().shouldParse())
return isType(Parser::StatementType::kStmtSelect);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -588,7 +590,9 @@ inline Optional<bool> Statement::isSelect() const
inline Optional<bool> Statement::isInsert() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return isType(Parser::StatementType::kStmtInsert);
if (_pImpl->session().shouldParse())
return isType(Parser::StatementType::kStmtInsert);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -598,7 +602,9 @@ inline Optional<bool> Statement::isInsert() const
inline Optional<bool> Statement::isUpdate() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return isType(Parser::StatementType::kStmtUpdate);
if (_pImpl->session().shouldParse())
return isType(Parser::StatementType::kStmtUpdate);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -608,7 +614,9 @@ inline Optional<bool> Statement::isUpdate() const
inline Optional<bool> Statement::isDelete() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return isType(Parser::StatementType::kStmtDelete);
if (_pImpl->session().shouldParse())
return isType(Parser::StatementType::kStmtDelete);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -618,7 +626,9 @@ inline Optional<bool> Statement::isDelete() const
inline Optional<bool> Statement::hasSelect() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return hasType(Parser::StatementType::kStmtSelect);
if (_pImpl->session().shouldParse())
return hasType(Parser::StatementType::kStmtSelect);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -628,7 +638,9 @@ inline Optional<bool> Statement::hasSelect() const
inline Optional<bool> Statement::hasInsert() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return hasType(Parser::StatementType::kStmtInsert);
if (_pImpl->session().shouldParse())
return hasType(Parser::StatementType::kStmtInsert);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -638,7 +650,9 @@ inline Optional<bool> Statement::hasInsert() const
inline Optional<bool> Statement::hasUpdate() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return hasType(Parser::StatementType::kStmtUpdate);
if (_pImpl->session().shouldParse())
return hasType(Parser::StatementType::kStmtUpdate);
else return Optional<bool>();
#else
return Optional<bool>();
#endif
@ -648,7 +662,9 @@ inline Optional<bool> Statement::hasUpdate() const
inline Optional<bool> Statement::hasDelete() const
{
#ifndef POCO_DATA_NO_SQL_PARSER
return hasType(Parser::StatementType::kStmtDelete);
if (_pImpl->session().shouldParse())
return hasType(Parser::StatementType::kStmtDelete);
else return Optional<bool>();
#else
return Optional<bool>();
#endif

View File

@ -259,6 +259,9 @@ protected:
SessionImpl& session();
/// Rteurns session associated with this statement.
const SessionImpl& session() const;
/// Rteurns session associated with this statement.
virtual AbstractBinding::BinderPtr binder() = 0;
/// Returns the concrete binder used by the statement.
@ -512,6 +515,12 @@ inline SessionImpl& StatementImpl::session()
}
inline const SessionImpl& StatementImpl::session() const
{
return _rSession;
}
inline void StatementImpl::setStorage(Storage storage)
{
_storage = storage;

View File

@ -232,7 +232,7 @@ void Statement::formatQuery()
void Statement::checkBeginTransaction()
{
SessionImpl& session = _pImpl->session();
if (!session.isAutocommit() && !session.isTransaction())
if (!session.isAutocommit() && !session.isTransaction() && session.shouldParse())
{
auto result = parse();
if (result.isSpecified() && result.value() && !isSelect().value())

View File

@ -1460,8 +1460,7 @@ void DataTest::testSQLParse()
assertTrue (!stmt.isDelete().value());
assertTrue (!stmt.hasDelete().value());
Session sess2(SessionFactory::instance().create("test", "cs"));
stmt.reset(sess2);
stmt.reset();
stmt = (sess << "INSERT INTO Test VALUES ('1', 2, 3.5);"
"SELECT * FROM Test WHERE First = ?;"
"UPDATE Test SET value=1 WHERE First = '1';"
@ -1480,6 +1479,29 @@ void DataTest::testSQLParse()
assertTrue (!stmt.isDelete().value());
assertTrue (stmt.hasDelete().value());
sess.setFeature("sqlParse", false);
assertTrue (!sess.getFeature("sqlParse"));
stmt.reset();
stmt = (sess << "INSERT INTO Test VALUES ('1', 2, 3.5);"
"SELECT * FROM Test WHERE First = ?;"
"UPDATE Test SET value=1 WHERE First = '1';"
"DELETE FROM Test WHERE First = ?;"
"DROP TABLE table_name;"
"ALTER TABLE mytable DROP COLUMN IF EXISTS mycolumn;"
"PREPARE prep_inst FROM 'INSERT INTO test VALUES (?, ?, ?)';"
"EXECUTE prep_inst(1, 2, 3);");
stmt.execute();
assertTrue (!stmt.isSelect().isSpecified());
assertTrue (!stmt.hasSelect().isSpecified());
assertTrue (!stmt.isUpdate().isSpecified());
assertTrue (!stmt.hasUpdate().isSpecified());
assertTrue (!stmt.isInsert().isSpecified());
assertTrue (!stmt.hasInsert().isSpecified());
assertTrue (!stmt.isDelete().isSpecified());
assertTrue (!stmt.hasDelete().isSpecified());
#endif // POCO_DATA_NO_SQL_PARSER
}

View File

@ -52,5 +52,5 @@ else
fi
cd "$basedir"/"$library"/testsuite/bin/"$OSNAME"/"$OSARCH"/ || exit
testrunner -all
testrunnerd -all
./testrunner -all
./testrunnerd -all