1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: objectnames.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dbaccess.hxx"
34 #ifndef DBACCESS_SOURCE_SDBTOOLS_CONNECTION_OBJECTNAMES_HXX
35 #include "objectnames.hxx"
38 #ifndef DBACCESS_MODULE_SDBT_HXX
39 #include "module_sdbt.hxx"
41 #ifndef DBACCESS_SDBT_RESOURCE_HRC
42 #include "sdbt_resource.hrc"
45 /** === begin UNO includes === **/
46 #include <com/sun/star/lang/NullPointerException.hpp>
47 #include <com/sun/star/sdb/CommandType.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
50 #include <com/sun/star/sdb/ErrorCondition.hpp>
51 /** === end UNO includes === **/
53 #include <connectivity/dbmetadata.hxx>
54 #include <connectivity/dbtools.hxx>
55 #include <connectivity/sqlerror.hxx>
56 #include <cppuhelper/exc_hlp.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <tools/string.hxx>
60 #include <boost/shared_ptr.hpp>
62 //........................................................................
65 //........................................................................
67 /** === begin UNO using === **/
68 using ::com::sun::star::uno::Reference
;
69 using ::com::sun::star::sdbc::XConnection
;
70 using ::com::sun::star::lang::NullPointerException
;
71 using ::com::sun::star::lang::IllegalArgumentException
;
72 using ::com::sun::star::uno::RuntimeException
;
73 using ::com::sun::star::sdbc::SQLException
;
74 using ::com::sun::star::sdbc::XDatabaseMetaData
;
75 using ::com::sun::star::uno::XInterface
;
76 using ::com::sun::star::container::XNameAccess
;
77 using ::com::sun::star::sdbc::XDatabaseMetaData
;
78 using ::com::sun::star::uno::UNO_QUERY_THROW
;
79 using ::com::sun::star::sdbcx::XTablesSupplier
;
80 using ::com::sun::star::sdb::XQueriesSupplier
;
81 using ::com::sun::star::uno::Exception
;
82 using ::com::sun::star::uno::makeAny
;
83 using ::com::sun::star::uno::Any
;
84 /** === end UNO using === **/
86 namespace CommandType
= ::com::sun::star::sdb::CommandType
;
87 namespace ErrorCondition
= ::com::sun::star::sdb::ErrorCondition
;
89 //====================================================================
91 //====================================================================
95 virtual bool validateName( const ::rtl::OUString
& _rName
) = 0;
96 virtual void validateName_throw( const ::rtl::OUString
& _rName
) = 0;
98 virtual ~INameValidation() { }
100 typedef ::boost::shared_ptr
< INameValidation
> PNameValidation
;
102 //====================================================================
103 //= PlainExistenceCheck
104 //====================================================================
105 class PlainExistenceCheck
: public INameValidation
108 const ::comphelper::ComponentContext m_aContext
;
109 Reference
< XConnection
> m_xConnection
;
110 Reference
< XNameAccess
> m_xContainer
;
113 PlainExistenceCheck( const ::comphelper::ComponentContext
& _rContext
, const Reference
< XConnection
>& _rxConnection
, const Reference
< XNameAccess
>& _rxContainer
)
114 :m_aContext( _rContext
)
115 ,m_xConnection( _rxConnection
)
116 ,m_xContainer( _rxContainer
)
118 OSL_ENSURE( m_xContainer
.is(), "PlainExistenceCheck::PlainExistenceCheck: this will crash!" );
122 virtual bool validateName( const ::rtl::OUString
& _rName
)
124 return !m_xContainer
->hasByName( _rName
);
127 virtual void validateName_throw( const ::rtl::OUString
& _rName
)
129 if ( validateName( _rName
) )
132 ::connectivity::SQLError
aErrors( m_aContext
);
133 SQLException
aError( aErrors
.getSQLException( ErrorCondition::DB_OBJECT_NAME_IS_USED
, m_xConnection
, _rName
) );
135 ::dbtools::DatabaseMetaData
aMeta( m_xConnection
);
136 if ( aMeta
.supportsSubqueriesInFrom() )
138 String
sNeedDistinctNames( SdbtRes( STR_QUERY_AND_TABLE_DISTINCT_NAMES
) );
139 aError
.NextException
<<= SQLException( sNeedDistinctNames
, m_xConnection
, ::rtl::OUString(), 0, Any() );
146 //====================================================================
147 //= TableValidityCheck
148 //====================================================================
149 class TableValidityCheck
: public INameValidation
151 const ::comphelper::ComponentContext m_aContext
;
152 const Reference
< XConnection
> m_xConnection
;
155 TableValidityCheck( const ::comphelper::ComponentContext
& _rContext
, const Reference
< XConnection
>& _rxConnection
)
156 :m_aContext( _rContext
)
157 ,m_xConnection( _rxConnection
)
161 virtual bool validateName( const ::rtl::OUString
& _rName
)
163 ::dbtools::DatabaseMetaData
aMeta( m_xConnection
);
164 if ( !aMeta
.restrictIdentifiersToSQL92() )
167 ::rtl::OUString sCatalog
, sSchema
, sName
;
168 ::dbtools::qualifiedNameComponents(
169 m_xConnection
->getMetaData(), _rName
, sCatalog
, sSchema
, sName
, ::dbtools::eInTableDefinitions
);
171 ::rtl::OUString
sExtraNameCharacters( m_xConnection
->getMetaData()->getExtraNameCharacters() );
172 if ( ( sCatalog
.getLength() && !::dbtools::isValidSQLName( sCatalog
, sExtraNameCharacters
) )
173 || ( sSchema
.getLength() && !::dbtools::isValidSQLName( sSchema
, sExtraNameCharacters
) )
174 || ( sName
.getLength() && !::dbtools::isValidSQLName( sName
, sExtraNameCharacters
) )
181 virtual void validateName_throw( const ::rtl::OUString
& _rName
)
183 if ( validateName( _rName
) )
186 ::connectivity::SQLError
aErrors( m_aContext
);
187 aErrors
.raiseException( ErrorCondition::DB_INVALID_SQL_NAME
, m_xConnection
, _rName
);
191 //====================================================================
192 //= QueryValidityCheck
193 //====================================================================
194 class QueryValidityCheck
: public INameValidation
196 const ::comphelper::ComponentContext m_aContext
;
197 const Reference
< XConnection
> m_xConnection
;
200 QueryValidityCheck( const ::comphelper::ComponentContext
& _rContext
, const Reference
< XConnection
>& _rxConnection
)
201 :m_aContext( _rContext
)
202 ,m_xConnection( _rxConnection
)
206 inline ::connectivity::ErrorCondition
validateName_getErrorCondition( const ::rtl::OUString
& _rName
)
208 if ( ( _rName
.indexOf( (sal_Unicode
)34 ) >= 0 ) // "
209 || ( _rName
.indexOf( (sal_Unicode
)39 ) >= 0 ) // '
210 || ( _rName
.indexOf( (sal_Unicode
)96 ) >= 0 ) //
211 || ( _rName
.indexOf( (sal_Unicode
)145 ) >= 0 ) //
212 || ( _rName
.indexOf( (sal_Unicode
)146 ) >= 0 ) //
213 || ( _rName
.indexOf( (sal_Unicode
)180 ) >= 0 ) // #86621# removed unparsable chars
215 return ErrorCondition::DB_QUERY_NAME_WITH_QUOTES
;
217 if ( _rName
.indexOf( '/') >= 0 )
218 return ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES
;
223 virtual bool validateName( const ::rtl::OUString
& _rName
)
225 if ( validateName_getErrorCondition( _rName
) != 0 )
230 virtual void validateName_throw( const ::rtl::OUString
& _rName
)
232 ::connectivity::ErrorCondition nErrorCondition
= validateName_getErrorCondition( _rName
);
233 if ( nErrorCondition
!= 0 )
235 ::connectivity::SQLError
aErrors( m_aContext
);
236 aErrors
.raiseException( nErrorCondition
, m_xConnection
);
241 //====================================================================
242 //= CombinedNameCheck
243 //====================================================================
244 class CombinedNameCheck
: public INameValidation
247 PNameValidation m_pPrimary
;
248 PNameValidation m_pSecondary
;
251 CombinedNameCheck( PNameValidation _pPrimary
, PNameValidation _pSecondary
)
252 :m_pPrimary( _pPrimary
)
253 ,m_pSecondary( _pSecondary
)
255 OSL_ENSURE( m_pPrimary
.get() && m_pSecondary
.get(), "CombinedNameCheck::CombinedNameCheck: this will crash!" );
259 virtual bool validateName( const ::rtl::OUString
& _rName
)
261 return m_pPrimary
->validateName( _rName
) && m_pSecondary
->validateName( _rName
);
264 virtual void validateName_throw( const ::rtl::OUString
& _rName
)
266 m_pPrimary
->validateName_throw( _rName
);
267 m_pSecondary
->validateName_throw( _rName
);
271 //====================================================================
273 //====================================================================
274 class NameCheckFactory
277 /** creates an INameValidation instance which can be used to check the existence of query or table names
280 the component's context
283 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be checked for existence
286 the connection relative to which the names are to be checked. Must be an SDB-level connection
288 @throws IllegalArgumentException
289 if the given connection is no SDB-level connection
291 @throws IllegalArgumentException
292 if the given command type is neither CommandType::TABLE or CommandType::QUERY
294 static PNameValidation
createExistenceCheck(
295 const ::comphelper::ComponentContext
& _rContext
,
296 sal_Int32 _nCommandType
,
297 const Reference
< XConnection
>& _rxConnection
300 /** creates an INameValidation instance which can be used to check the validity of a query or table name
303 the component's context
306 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be validated
309 the connection relative to which the names are to be checked. Must be an SDB-level connection
311 @throws IllegalArgumentException
312 if the given connection is no SDB-level connection
314 @throws IllegalArgumentException
315 if the given command type is neither CommandType::TABLE or CommandType::QUERY
317 static PNameValidation
createValidityCheck(
318 const ::comphelper::ComponentContext
& _rContext
,
319 const sal_Int32 _nCommandType
,
320 const Reference
< XConnection
>& _rxConnection
324 NameCheckFactory(); // never implemented
327 static void verifyCommandType( sal_Int32 _nCommandType
);
330 //--------------------------------------------------------------------
331 void NameCheckFactory::verifyCommandType( sal_Int32 _nCommandType
)
333 if ( ( _nCommandType
!= CommandType::TABLE
)
334 && ( _nCommandType
!= CommandType::QUERY
)
336 throw IllegalArgumentException(
337 String( SdbtRes( STR_INVALID_COMMAND_TYPE
) ),
343 //--------------------------------------------------------------------
344 PNameValidation
NameCheckFactory::createExistenceCheck( const ::comphelper::ComponentContext
& _rContext
, sal_Int32 _nCommandType
, const Reference
< XConnection
>& _rxConnection
)
346 verifyCommandType( _nCommandType
);
348 ::dbtools::DatabaseMetaData
aMeta( _rxConnection
);
350 Reference
< XNameAccess
> xTables
, xQueries
;
353 Reference
< XTablesSupplier
> xSuppTables( _rxConnection
, UNO_QUERY_THROW
);
354 Reference
< XQueriesSupplier
> xQueriesSupplier( _rxConnection
, UNO_QUERY_THROW
);
355 xTables
.set( xSuppTables
->getTables(), UNO_QUERY_THROW
);
356 xQueries
.set( xQueriesSupplier
->getQueries(), UNO_QUERY_THROW
);
358 catch( const Exception
& )
360 throw IllegalArgumentException(
361 String( SdbtRes( STR_CONN_WITHOUT_QUERIES_OR_TABLES
) ),
367 PNameValidation
pTableCheck( new PlainExistenceCheck( _rContext
, _rxConnection
, xTables
) );
368 PNameValidation
pQueryCheck( new PlainExistenceCheck( _rContext
, _rxConnection
, xQueries
) );
369 PNameValidation pReturn
;
371 if ( aMeta
.supportsSubqueriesInFrom() )
372 pReturn
.reset( new CombinedNameCheck( pTableCheck
, pQueryCheck
) );
373 else if ( _nCommandType
== CommandType::TABLE
)
374 pReturn
= pTableCheck
;
376 pReturn
= pQueryCheck
;
380 //--------------------------------------------------------------------
381 PNameValidation
NameCheckFactory::createValidityCheck( const ::comphelper::ComponentContext
& _rContext
, sal_Int32 _nCommandType
, const Reference
< XConnection
>& _rxConnection
)
383 verifyCommandType( _nCommandType
);
385 Reference
< XDatabaseMetaData
> xMeta
;
388 xMeta
.set( _rxConnection
->getMetaData(), UNO_QUERY_THROW
);
390 catch( const Exception
& )
392 throw IllegalArgumentException(
393 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The connection could not provide its database's meta data." ) ),
399 if ( _nCommandType
== CommandType::TABLE
)
400 return PNameValidation( new TableValidityCheck( _rContext
, _rxConnection
) );
401 return PNameValidation( new QueryValidityCheck( _rContext
, _rxConnection
) );
404 //====================================================================
406 //====================================================================
407 struct ObjectNames_Impl
409 SdbtClient m_aModuleClient
; // keep the module alive as long as this instance lives
412 //====================================================================
414 //====================================================================
415 //--------------------------------------------------------------------
416 ObjectNames::ObjectNames( const ::comphelper::ComponentContext
& _rContext
, const Reference
< XConnection
>& _rxConnection
)
417 :ConnectionDependentComponent( _rContext
)
418 ,m_pImpl( new ObjectNames_Impl
)
420 if ( !_rxConnection
.is() )
421 throw NullPointerException();
422 setWeakConnection( _rxConnection
);
425 //--------------------------------------------------------------------
426 ObjectNames::~ObjectNames()
430 //--------------------------------------------------------------------
431 ::rtl::OUString SAL_CALL
ObjectNames::suggestName( ::sal_Int32 _CommandType
, const ::rtl::OUString
& _BaseName
) throw (IllegalArgumentException
, RuntimeException
)
433 EntryGuard
aGuard( *this );
435 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( getContext(), _CommandType
, getConnection() ) );
437 String
sBaseName( _BaseName
);
438 if ( sBaseName
.Len() == 0 )
440 if ( _CommandType
== CommandType::TABLE
)
441 sBaseName
= String( SdbtRes( STR_BASENAME_TABLE
) );
443 sBaseName
= String( SdbtRes( STR_BASENAME_QUERY
) );
446 ::rtl::OUString
sName( sBaseName
);
448 while ( !pNameCheck
->validateName( sName
) )
450 ::rtl::OUStringBuffer aNameBuffer
;
451 aNameBuffer
.append( sBaseName
);
452 aNameBuffer
.appendAscii( " " );
453 aNameBuffer
.append( (sal_Int32
)++i
);
454 sName
= aNameBuffer
.makeStringAndClear();
460 //--------------------------------------------------------------------
461 ::rtl::OUString SAL_CALL
ObjectNames::convertToSQLName( const ::rtl::OUString
& Name
) throw (RuntimeException
)
463 EntryGuard
aGuard( *this );
464 Reference
< XDatabaseMetaData
> xMeta( getConnection()->getMetaData(), UNO_QUERY_THROW
);
465 return ::dbtools::convertName2SQLName( Name
, xMeta
->getExtraNameCharacters() );
468 //--------------------------------------------------------------------
469 ::sal_Bool SAL_CALL
ObjectNames::isNameUsed( ::sal_Int32 _CommandType
, const ::rtl::OUString
& _Name
) throw (IllegalArgumentException
, RuntimeException
)
471 EntryGuard
aGuard( *this );
473 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( getContext(), _CommandType
, getConnection()) );
474 return !pNameCheck
->validateName( _Name
);
477 //--------------------------------------------------------------------
478 ::sal_Bool SAL_CALL
ObjectNames::isNameValid( ::sal_Int32 _CommandType
, const ::rtl::OUString
& _Name
) throw (IllegalArgumentException
, RuntimeException
)
480 EntryGuard
aGuard( *this );
482 PNameValidation
pNameCheck( NameCheckFactory::createValidityCheck( getContext(), _CommandType
, getConnection()) );
483 return pNameCheck
->validateName( _Name
);
486 //--------------------------------------------------------------------
487 void SAL_CALL
ObjectNames::checkNameForCreate( ::sal_Int32 _CommandType
, const ::rtl::OUString
& _Name
) throw (SQLException
, RuntimeException
)
489 EntryGuard
aGuard( *this );
491 PNameValidation
pNameCheck( NameCheckFactory::createExistenceCheck( getContext(), _CommandType
, getConnection() ) );
492 pNameCheck
->validateName_throw( _Name
);
494 pNameCheck
= NameCheckFactory::createValidityCheck( getContext(), _CommandType
, getConnection() );
495 pNameCheck
->validateName_throw( _Name
);
498 //........................................................................
499 } // namespace sdbtools
500 //........................................................................