Browse Source

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

Alex Fabijanic 2 years ago
parent
commit
afd9c8c408

+ 27 - 2
Data/include/Poco/Data/AbstractSessionImpl.h

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

+ 10 - 1
Data/include/Poco/Data/SessionImpl.h

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

+ 24 - 8
Data/include/Poco/Data/Statement.h

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

+ 9 - 0
Data/include/Poco/Data/StatementImpl.h

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

+ 1 - 1
Data/src/Statement.cpp

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

+ 24 - 2
Data/testsuite/src/DataTest.cpp

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

+ 2 - 2
runLibTests.sh

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