Kaydet (Commit) a29d97e6 authored tarafından Lionel Elie Mamane's avatar Lionel Elie Mamane

tdf#104986 move named parameters substitution into generic layer

Previously, drivers were responsible for making the substitution themselves.
In practice they all (Firebird, ODBC and JDBC) used the LibreOffice SQL
parser to parse the SQL statement and do the substitution.

This had a few negative consequences:
 * The substitition was applied to _all_ SQL commands, including
   queries having the "execute SQL directly" bit set. Which means
   that the SQL was _not_ sent to the DBMS exactly as typed by
   the user. Even if there was no substitution to be made, since
   the SQL command was always round-tripped through the parser,
   thus "normalising" it (which is what led to tdf#104986).
 * "execute SQL directly" queries "magically" behaved slightly
   differently depending on whether the LibreOffice SQL parser
   succeeded in parsing them or not.

Change-Id: Ieedc643f33467435a139e2565a01e6f398af041f
Reviewed-on: https://gerrit.libreoffice.org/47283Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarLionel Elie Mamane <lionel@mamane.lu>
üst 1bbadad7
...@@ -61,6 +61,11 @@ ...@@ -61,6 +61,11 @@
<value>false</value> <value>false</value>
</prop> </prop>
</node> </node>
<node oor:name="ParameterNameSubstitution" oor:op="replace">
<prop oor:name="Value" oor:type="xs:boolean">
<value>true</value>
</prop>
</node>
</node><!--Properties--> </node><!--Properties-->
<node oor:name="Features"> <node oor:name="Features">
</node><!--Features--> </node><!--Features-->
...@@ -95,6 +100,11 @@ ...@@ -95,6 +100,11 @@
<value>false</value> <value>false</value>
</prop> </prop>
</node> </node>
<node oor:name="ParameterNameSubstitution" oor:op="replace">
<prop oor:name="Value" oor:type="xs:boolean">
<value>true</value>
</prop>
</node>
</node> </node>
<node oor:name="Features"> <node oor:name="Features">
</node> </node>
......
...@@ -301,6 +301,15 @@ namespace dbtools ...@@ -301,6 +301,15 @@ namespace dbtools
return doGenerate; return doGenerate;
} }
bool DatabaseMetaData::shouldSubstituteParameterNames() const
{
bool doSubstitute( true );
Any setting;
if ( lcl_getConnectionSetting( "ParameterNameSubstitution", *m_pImpl, setting ) )
OSL_VERIFY( setting >>= doSubstitute );
return doSubstitute;
}
bool DatabaseMetaData::isAutoIncrementPrimaryKey() const bool DatabaseMetaData::isAutoIncrementPrimaryKey() const
{ {
bool is( true ); bool is( true );
......
...@@ -393,30 +393,6 @@ Reference< XStatement > SAL_CALL Connection::createStatement( ) ...@@ -393,30 +393,6 @@ Reference< XStatement > SAL_CALL Connection::createStatement( )
return xReturn; return xReturn;
} }
OUString Connection::transformPreparedStatement(const OUString& _sSQL)
{
OUString sSqlStatement (_sSQL);
try
{
OSQLParser aParser( m_xDriver->getContext() );
OUString sErrorMessage;
OUString sNewSql;
OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
if(pNode)
{ // special handling for parameters
OSQLParseNode::substituteParameterNames(pNode);
pNode->parseNodeToStr( sNewSql, this );
delete pNode;
sSqlStatement = sNewSql;
}
}
catch(const Exception&)
{
SAL_WARN("connectivity.firebird", "failed to remove named parameters from '" << _sSQL << "'");
}
return sSqlStatement;
}
Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement( Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
const OUString& _sSql) const OUString& _sSql)
{ {
...@@ -428,10 +404,7 @@ Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement( ...@@ -428,10 +404,7 @@ Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
if(m_aTypeInfo.empty()) if(m_aTypeInfo.empty())
buildTypeInfo(); buildTypeInfo();
OUString sSqlStatement (transformPreparedStatement( _sSql )); Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql);
Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,
sSqlStatement);
m_aStatements.push_back(WeakReferenceHelper(xReturn)); m_aStatements.push_back(WeakReferenceHelper(xReturn));
return xReturn; return xReturn;
......
...@@ -169,14 +169,6 @@ namespace connectivity ...@@ -169,14 +169,6 @@ namespace connectivity
void setupTransaction(); void setupTransaction();
void disposeStatements(); void disposeStatements();
/** transform named parameters into unnamed parameters
@param _sSQL
The SQL statement to transform.
@return
The new statement with unnamed parameters
*/
OUString transformPreparedStatement(const OUString& _sSQL);
public: public:
explicit Connection(FirebirdDriver* _pDriver); explicit Connection(FirebirdDriver* _pDriver);
virtual ~Connection() override; virtual ~Connection() override;
......
...@@ -266,7 +266,6 @@ java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver ) ...@@ -266,7 +266,6 @@ java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
,m_pDriverClassLoader() ,m_pDriverClassLoader()
,m_Driver_theClass(nullptr) ,m_Driver_theClass(nullptr)
,m_aLogger( _rDriver.getLogger() ) ,m_aLogger( _rDriver.getLogger() )
,m_bParameterSubstitution(false)
,m_bIgnoreDriverPrivileges(true) ,m_bIgnoreDriverPrivileges(true)
,m_bIgnoreCurrency(false) ,m_bIgnoreCurrency(false)
{ {
...@@ -464,32 +463,6 @@ Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) ...@@ -464,32 +463,6 @@ Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( )
return xStmt; return xStmt;
} }
OUString java_sql_Connection::transFormPreparedStatement(const OUString& _sSQL)
{
OUString sSqlStatement = _sSQL;
if ( m_bParameterSubstitution )
{
try
{
OSQLParser aParser( m_pDriver->getContext() );
OUString sErrorMessage;
OUString sNewSql;
OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
if(pNode)
{ // special handling for parameters
OSQLParseNode::substituteParameterNames(pNode);
pNode->parseNodeToStr( sNewSql, this );
delete pNode;
sSqlStatement = sNewSql;
}
}
catch(const Exception&)
{
}
}
return sSqlStatement;
}
Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql ) Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql )
{ {
::osl::MutexGuard aGuard( m_aMutex ); ::osl::MutexGuard aGuard( m_aMutex );
...@@ -497,10 +470,8 @@ Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( ...@@ -497,10 +470,8 @@ Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement(
m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql ); m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
SDBThreadAttach t; SDBThreadAttach t;
OUString sSqlStatement = sql;
sSqlStatement = transFormPreparedStatement( sSqlStatement );
java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement ); java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sql );
Reference< XPreparedStatement > xReturn( pStatement ); Reference< XPreparedStatement > xReturn( pStatement );
m_aStatements.push_back(WeakReferenceHelper(xReturn)); m_aStatements.push_back(WeakReferenceHelper(xReturn));
...@@ -515,10 +486,8 @@ Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const ...@@ -515,10 +486,8 @@ Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const
m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql ); m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
SDBThreadAttach t; SDBThreadAttach t;
OUString sSqlStatement = sql;
sSqlStatement = transFormPreparedStatement( sSqlStatement );
java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement ); java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sql );
Reference< XPreparedStatement > xStmt( pStatement ); Reference< XPreparedStatement > xStmt( pStatement );
m_aStatements.push_back(WeakReferenceHelper(xStmt)); m_aStatements.push_back(WeakReferenceHelper(xStmt));
...@@ -784,7 +753,6 @@ bool java_sql_Connection::construct(const OUString& url, ...@@ -784,7 +753,6 @@ bool java_sql_Connection::construct(const OUString& url,
sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass); sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled ); bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement ); sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges ); m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency ); m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties ); aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
......
...@@ -53,7 +53,6 @@ OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver) ...@@ -53,7 +53,6 @@ OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver)
,m_bClosed(false) ,m_bClosed(false)
,m_bUseCatalog(false) ,m_bUseCatalog(false)
,m_bUseOldDateFormat(false) ,m_bUseOldDateFormat(false)
,m_bParameterSubstitution(false)
,m_bIgnoreDriverPrivileges(false) ,m_bIgnoreDriverPrivileges(false)
,m_bPreventGetVersionColumns(false) ,m_bPreventGetVersionColumns(false)
,m_bReadOnly(true) ,m_bReadOnly(true)
...@@ -200,8 +199,6 @@ SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyVal ...@@ -200,8 +199,6 @@ SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyVal
OSL_VERIFY( pBegin->Value >>= m_bIgnoreDriverPrivileges ); OSL_VERIFY( pBegin->Value >>= m_bIgnoreDriverPrivileges );
else if( pBegin->Name == "PreventGetVersionColumns") else if( pBegin->Name == "PreventGetVersionColumns")
OSL_VERIFY( pBegin->Value >>= m_bPreventGetVersionColumns ); OSL_VERIFY( pBegin->Value >>= m_bPreventGetVersionColumns );
else if( pBegin->Name == "ParameterNameSubstitution")
OSL_VERIFY( pBegin->Value >>= m_bParameterSubstitution );
else if( pBegin->Name == "IsAutoRetrievingEnabled") else if( pBegin->Name == "IsAutoRetrievingEnabled")
{ {
bool bAutoRetrievingEnabled = false; bool bAutoRetrievingEnabled = false;
......
...@@ -69,25 +69,6 @@ OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString ...@@ -69,25 +69,6 @@ OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString
,m_bPrepared(false) ,m_bPrepared(false)
{ {
m_sSqlStatement = sql; m_sSqlStatement = sql;
try
{
if(_pConnection->isParameterSubstitutionEnabled())
{
OSQLParser aParser( comphelper::getComponentContext(_pConnection->getDriver()->getORB()) );
OUString sErrorMessage;
OUString sNewSql;
std::unique_ptr<OSQLParseNode> pNode( aParser.parseTree(sErrorMessage,sql) );
if ( pNode.get() )
{ // special handling for parameters
OSQLParseNode::substituteParameterNames(pNode.get());
pNode->parseNodeToStr( sNewSql, _pConnection );
m_sSqlStatement = sNewSql;
}
}
}
catch(Exception&)
{
}
} }
void SAL_CALL OPreparedStatement::acquire() throw() void SAL_CALL OPreparedStatement::acquire() throw()
......
...@@ -69,7 +69,6 @@ namespace connectivity ...@@ -69,7 +69,6 @@ namespace connectivity
bool m_bClosed; bool m_bClosed;
bool m_bUseCatalog; // should we use the catalog on filebased databases bool m_bUseCatalog; // should we use the catalog on filebased databases
bool m_bUseOldDateFormat; bool m_bUseOldDateFormat;
bool m_bParameterSubstitution;
bool m_bIgnoreDriverPrivileges; bool m_bIgnoreDriverPrivileges;
bool m_bPreventGetVersionColumns; // #i60273# bool m_bPreventGetVersionColumns; // #i60273#
bool m_bReadOnly; bool m_bReadOnly;
...@@ -122,7 +121,6 @@ namespace connectivity ...@@ -122,7 +121,6 @@ namespace connectivity
// should we use the catalog on filebased databases // should we use the catalog on filebased databases
bool isCatalogUsed() const { return m_bUseCatalog; } bool isCatalogUsed() const { return m_bUseCatalog; }
bool isParameterSubstitutionEnabled() const { return m_bParameterSubstitution; }
bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges; } bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges; }
bool preventGetVersionColumns() const { return m_bPreventGetVersionColumns; } bool preventGetVersionColumns() const { return m_bPreventGetVersionColumns; }
bool useOldDateFormat() const { return m_bUseOldDateFormat; } bool useOldDateFormat() const { return m_bUseOldDateFormat; }
......
...@@ -397,6 +397,10 @@ void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const ...@@ -397,6 +397,10 @@ void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const
rString.append(" "); rString.append(" ");
if (nCount == 1) // ? if (nCount == 1) // ?
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
else if (rParam.bParseToSDBCLevel && rParam.aMetaData.shouldSubstituteParameterNames())
{
rString.append("?");
}
else if (nCount == 2) // :Name else if (nCount == 2) // :Name
{ {
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
...@@ -404,6 +408,7 @@ void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const ...@@ -404,6 +408,7 @@ void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const
} // [Name] } // [Name]
else else
{ {
assert (nCount == 3);
m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false );
rString.append(m_aChildren[1]->m_aNodeValue); rString.append(m_aChildren[1]->m_aNodeValue);
rString.append(m_aChildren[2]->m_aNodeValue); rString.append(m_aChildren[2]->m_aNodeValue);
......
...@@ -135,6 +135,10 @@ namespace dbtools ...@@ -135,6 +135,10 @@ namespace dbtools
*/ */
bool shouldEscapeDateTime() const; bool shouldEscapeDateTime() const;
/** should named parameters (:foo, [foo]) be replaced by unnamed parameters (?)
*/
bool shouldSubstituteParameterNames() const;
/** auto increment columns should be automatically used as primary key. /** auto increment columns should be automatically used as primary key.
*/ */
bool isAutoIncrementPrimaryKey() const; bool isAutoIncrementPrimaryKey() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment