1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "objectnames.hxx"
21 #include <core_resource.hxx>
23 #include <strings.hrc>
25 #include <com/sun/star/sdb/CommandType.hpp>
26 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
27 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
28 #include <com/sun/star/sdb/ErrorCondition.hpp>
30 #include <connectivity/dbmetadata.hxx>
31 #include <connectivity/dbtools.hxx>
32 #include <connectivity/sqlerror.hxx>
33 #include <osl/diagnose.h>
41 using ::com::sun::star::uno::Reference
;
42 using ::com::sun::star::sdbc::XConnection
;
43 using ::com::sun::star::lang::IllegalArgumentException
;
44 using ::com::sun::star::sdbc::SQLException
;
45 using ::com::sun::star::sdbc::XDatabaseMetaData
;
46 using ::com::sun::star::container::XNameAccess
;
47 using ::com::sun::star::uno::UNO_QUERY_THROW
;
48 using ::com::sun::star::sdbcx::XTablesSupplier
;
49 using ::com::sun::star::sdb::XQueriesSupplier
;
50 using ::com::sun::star::uno::Exception
;
51 using ::com::sun::star::uno::Any
;
52 using ::com::sun::star::uno::XComponentContext
;
54 namespace CommandType
= ::com::sun::star::sdb::CommandType
;
55 namespace ErrorCondition
= ::com::sun::star::sdb::ErrorCondition
;
63 virtual bool validateName( const OUString
& _rName
) = 0;
64 virtual void validateName_throw( const OUString
& _rName
) = 0;
66 virtual ~INameValidation() { }
71 typedef std::shared_ptr
< INameValidation
> PNameValidation
;
75 // PlainExistenceCheck
76 class PlainExistenceCheck
: public INameValidation
79 Reference
< XConnection
> m_xConnection
;
80 Reference
< XNameAccess
> m_xContainer
;
83 PlainExistenceCheck( const Reference
< XConnection
>& _rxConnection
, const Reference
< XNameAccess
>& _rxContainer
)
84 :m_xConnection( _rxConnection
)
85 ,m_xContainer( _rxContainer
)
87 OSL_ENSURE( m_xContainer
.is(), "PlainExistenceCheck::PlainExistenceCheck: this will crash!" );
91 virtual bool validateName( const OUString
& _rName
) override
93 return !m_xContainer
->hasByName( _rName
);
96 virtual void validateName_throw( const OUString
& _rName
) override
98 if ( validateName( _rName
) )
101 ::connectivity::SQLError aErrors
;
102 SQLException
aError( aErrors
.getSQLException( ErrorCondition::DB_OBJECT_NAME_IS_USED
, m_xConnection
, _rName
) );
104 ::dbtools::DatabaseMetaData
aMeta( m_xConnection
);
105 if ( aMeta
.supportsSubqueriesInFrom() )
107 OUString
sNeedDistinctNames( DBA_RES( STR_QUERY_AND_TABLE_DISTINCT_NAMES
) );
108 aError
.NextException
<<= SQLException( sNeedDistinctNames
, m_xConnection
, OUString(), 0, Any() );
115 // TableValidityCheck
116 class TableValidityCheck
: public INameValidation
118 const Reference
< XConnection
> m_xConnection
;
121 TableValidityCheck( const Reference
< XConnection
>& _rxConnection
)
122 :m_xConnection( _rxConnection
)
126 virtual bool validateName( const OUString
& _rName
) override
128 ::dbtools::DatabaseMetaData
aMeta( m_xConnection
);
129 if ( !aMeta
.restrictIdentifiersToSQL92() )
132 OUString sCatalog
, sSchema
, sName
;
133 ::dbtools::qualifiedNameComponents(
134 m_xConnection
->getMetaData(), _rName
, sCatalog
, sSchema
, sName
, ::dbtools::EComposeRule::InTableDefinitions
);
136 OUString
sExtraNameCharacters( m_xConnection
->getMetaData()->getExtraNameCharacters() );
137 return !( ( !sCatalog
.isEmpty() && !::dbtools::isValidSQLName( sCatalog
, sExtraNameCharacters
) )
138 || ( !sSchema
.isEmpty() && !::dbtools::isValidSQLName( sSchema
, sExtraNameCharacters
) )
139 || ( !sName
.isEmpty() && !::dbtools::isValidSQLName( sName
, sExtraNameCharacters
) ));
142 virtual void validateName_throw( const OUString
& _rName
) override
144 if ( validateName( _rName
) )
147 ::connectivity::SQLError aErrors
;
148 aErrors
.raiseException( ErrorCondition::DB_INVALID_SQL_NAME
, m_xConnection
, _rName
);
152 // QueryValidityCheck
153 class QueryValidityCheck
: public INameValidation
155 const Reference
< XConnection
> m_xConnection
;
158 QueryValidityCheck( const Reference
< XConnection
>& _rxConnection
)
159 :m_xConnection( _rxConnection
)
163 static ::connectivity::ErrorCondition
validateName_getErrorCondition( std::u16string_view _rName
)
165 if ( ( _rName
.find( u
'"' ) != std::u16string_view::npos
)
166 || ( _rName
.find( u
'\'' ) != std::u16string_view::npos
)
167 || ( _rName
.find( u
'`' ) != std::u16string_view::npos
)
168 || ( _rName
.find( u
'\x0091' ) != std::u16string_view::npos
)
169 || ( _rName
.find( u
'\x0092' ) != std::u16string_view::npos
)
170 || ( _rName
.find( u
'\x00B4' ) != std::u16string_view::npos
) // removed unparsable chars
172 return ErrorCondition::DB_QUERY_NAME_WITH_QUOTES
;
174 if ( _rName
.find( '/') != std::u16string_view::npos
)
175 return ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES
;
180 virtual bool validateName( const OUString
& _rName
) override
182 return validateName_getErrorCondition( _rName
) == 0;
185 virtual void validateName_throw( const OUString
& _rName
) override
187 ::connectivity::ErrorCondition nErrorCondition
= validateName_getErrorCondition( _rName
);
188 if ( nErrorCondition
!= 0 )
190 ::connectivity::SQLError aErrors
;
191 aErrors
.raiseException( nErrorCondition
, m_xConnection
);
197 class CombinedNameCheck
: public INameValidation
200 PNameValidation m_pPrimary
;
201 PNameValidation m_pSecondary
;
204 CombinedNameCheck(PNameValidation _pPrimary
, PNameValidation _pSecondary
)
205 :m_pPrimary(std::move( _pPrimary
))
206 ,m_pSecondary(std::move( _pSecondary
))
208 OSL_ENSURE( m_pPrimary
&& m_pSecondary
, "CombinedNameCheck::CombinedNameCheck: this will crash!" );
212 virtual bool validateName( const OUString
& _rName
) override
214 return m_pPrimary
->validateName( _rName
) && m_pSecondary
->validateName( _rName
);
217 virtual void validateName_throw( const OUString
& _rName
) override
219 m_pPrimary
->validateName_throw( _rName
);
220 m_pSecondary
->validateName_throw( _rName
);
225 class NameCheckFactory
228 NameCheckFactory(const NameCheckFactory
&) = delete;
229 const NameCheckFactory
& operator=(const NameCheckFactory
&) = delete;
230 /** creates an INameValidation instance which can be used to check the existence of query or table names
233 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be checked for existence
236 the connection relative to which the names are to be checked. Must be an SDB-level connection
238 @throws IllegalArgumentException
239 if the given connection is no SDB-level connection
241 @throws IllegalArgumentException
242 if the given command type is neither CommandType::TABLE or CommandType::QUERY
244 static PNameValidation
createExistenceCheck(
245 sal_Int32 _nCommandType
,
246 const Reference
< XConnection
>& _rxConnection
249 /** creates an INameValidation instance which can be used to check the validity of a query or table name
252 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be validated
255 the connection relative to which the names are to be checked. Must be an SDB-level connection
257 @throws IllegalArgumentException
258 if the given connection is no SDB-level connection
260 @throws IllegalArgumentException
261 if the given command type is neither CommandType::TABLE or CommandType::QUERY
263 static PNameValidation
createValidityCheck(
264 const sal_Int32 _nCommandType
,
265 const Reference
< XConnection
>& _rxConnection
269 static void verifyCommandType( sal_Int32 _nCommandType
);
274 void NameCheckFactory::verifyCommandType( sal_Int32 _nCommandType
)
276 if ( ( _nCommandType
!= CommandType::TABLE
)
277 && ( _nCommandType
!= CommandType::QUERY
)
279 throw IllegalArgumentException(
280 DBA_RES( STR_INVALID_COMMAND_TYPE
),
286 PNameValidation
NameCheckFactory::createExistenceCheck( sal_Int32 _nCommandType
, const Reference
< XConnection
>& _rxConnection
)
288 verifyCommandType( _nCommandType
);
290 ::dbtools::DatabaseMetaData
aMeta( _rxConnection
);
292 Reference
< XNameAccess
> xTables
, xQueries
;
295 Reference
< XTablesSupplier
> xSuppTables( _rxConnection
, UNO_QUERY_THROW
);
296 Reference
< XQueriesSupplier
> xQueriesSupplier( _rxConnection
, UNO_QUERY_THROW
);
297 xTables
.set( xSuppTables
->getTables(), css::uno::UNO_SET_THROW
);
298 xQueries
.set( xQueriesSupplier
->getQueries(), css::uno::UNO_SET_THROW
);
300 catch( const Exception
& )
302 throw IllegalArgumentException(
303 DBA_RES( STR_CONN_WITHOUT_QUERIES_OR_TABLES
),
309 PNameValidation pTableCheck
= std::make_shared
<PlainExistenceCheck
>( _rxConnection
, xTables
);
310 PNameValidation pQueryCheck
= std::make_shared
<PlainExistenceCheck
>( _rxConnection
, xQueries
);
311 PNameValidation pReturn
;
313 if ( aMeta
.supportsSubqueriesInFrom() )
314 pReturn
= std::make_shared
<CombinedNameCheck
>( pTableCheck
, pQueryCheck
);
315 else if ( _nCommandType
== CommandType::TABLE
)
316 pReturn
= std::move(pTableCheck
);
318 pReturn
= std::move(pQueryCheck
);
322 PNameValidation
NameCheckFactory::createValidityCheck( sal_Int32 _nCommandType
, const Reference
< XConnection
>& _rxConnection
)
324 verifyCommandType( _nCommandType
);
326 Reference
< XDatabaseMetaData
> xMeta
;
329 xMeta
.set( _rxConnection
->getMetaData(), css::uno::UNO_SET_THROW
);
331 catch( const Exception
& )
333 throw IllegalArgumentException(
334 u
"The connection could not provide its database's meta data."_ustr
,
340 if ( _nCommandType
== CommandType::TABLE
)
341 return std::make_shared
<TableValidityCheck
>( _rxConnection
);
342 return std::make_shared
<QueryValidityCheck
>( _rxConnection
);
346 ObjectNames::ObjectNames( const Reference
<XComponentContext
>& _rContext
, const Reference
< XConnection
>& _rxConnection
)
347 :ConnectionDependentComponent( _rContext
)
349 setWeakConnection( _rxConnection
);
352 ObjectNames::~ObjectNames()
356 OUString SAL_CALL
ObjectNames::suggestName( ::sal_Int32 CommandType
, const OUString
& BaseName
)
358 EntryGuard
aGuard( *this );
360 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( CommandType
, getConnection() ) );
362 OUString
sBaseName( BaseName
);
363 if ( sBaseName
.isEmpty() )
365 if ( CommandType
== CommandType::TABLE
)
366 sBaseName
= DBA_RES(STR_BASENAME_TABLE
);
368 sBaseName
= DBA_RES(STR_BASENAME_QUERY
);
370 else if( CommandType
== CommandType::QUERY
)
372 sBaseName
=sBaseName
.replace('/', '_');
375 OUString
sName( sBaseName
);
377 while ( !pNameCheck
->validateName( sName
) )
379 sName
= sBaseName
+ " " + OUString::number(++i
);
385 OUString SAL_CALL
ObjectNames::convertToSQLName( const OUString
& Name
)
387 EntryGuard
aGuard( *this );
388 Reference
< XDatabaseMetaData
> xMeta( getConnection()->getMetaData(), css::uno::UNO_SET_THROW
);
389 return ::dbtools::convertName2SQLName( Name
, xMeta
->getExtraNameCharacters() );
392 sal_Bool SAL_CALL
ObjectNames::isNameUsed( ::sal_Int32 CommandType
, const OUString
& Name
)
394 EntryGuard
aGuard( *this );
396 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( CommandType
, getConnection()) );
397 return !pNameCheck
->validateName( Name
);
400 sal_Bool SAL_CALL
ObjectNames::isNameValid( ::sal_Int32 CommandType
, const OUString
& Name
)
402 EntryGuard
aGuard( *this );
404 PNameValidation
pNameCheck( NameCheckFactory::createValidityCheck( CommandType
, getConnection()) );
405 return pNameCheck
->validateName( Name
);
408 void SAL_CALL
ObjectNames::checkNameForCreate( ::sal_Int32 CommandType
, const OUString
& Name
)
410 EntryGuard
aGuard( *this );
412 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( CommandType
, getConnection() ) );
413 pNameCheck
->validateName_throw( Name
);
415 pNameCheck
= NameCheckFactory::createValidityCheck( CommandType
, getConnection() );
416 pNameCheck
->validateName_throw( Name
);
419 } // namespace sdbtools
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */