tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / dbaccess / source / sdbtools / connection / objectnames.cxx
blobfe1caa97289a6f0ae58f0d3ac24341f3876e4ecb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
35 #include <memory>
36 #include <utility>
38 namespace sdbtools
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;
57 namespace {
59 // INameValidation
60 class INameValidation
62 public:
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;
73 namespace {
75 // PlainExistenceCheck
76 class PlainExistenceCheck : public INameValidation
78 private:
79 Reference< XConnection > m_xConnection;
80 Reference< XNameAccess > m_xContainer;
82 public:
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!" );
90 // INameValidation
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 ) )
99 return;
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() );
111 throw aError;
115 // TableValidityCheck
116 class TableValidityCheck : public INameValidation
118 const Reference< XConnection > m_xConnection;
120 public:
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() )
130 return true;
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 ) )
145 return;
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;
157 public:
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;
177 return 0;
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 );
196 // CombinedNameCheck
197 class CombinedNameCheck : public INameValidation
199 private:
200 PNameValidation m_pPrimary;
201 PNameValidation m_pSecondary;
203 public:
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!" );
211 // INameValidation
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 );
224 // NameCheckFactory
225 class NameCheckFactory
227 public:
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
232 @param _nCommandType
233 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be checked for existence
235 @param _rxConnection
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
251 @param _nCommandType
252 the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be validated
254 @param _rxConnection
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
268 private:
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 ),
281 nullptr,
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 ),
304 nullptr,
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);
317 else
318 pReturn = std::move(pQueryCheck);
319 return pReturn;
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,
335 nullptr,
340 if ( _nCommandType == CommandType::TABLE )
341 return std::make_shared<TableValidityCheck>( _rxConnection );
342 return std::make_shared<QueryValidityCheck>( _rxConnection );
345 // ObjectNames
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);
367 else
368 sBaseName = DBA_RES(STR_BASENAME_QUERY);
370 else if( CommandType == CommandType::QUERY )
372 sBaseName=sBaseName.replace('/', '_');
375 OUString sName( sBaseName );
376 sal_Int32 i = 1;
377 while ( !pNameCheck->validateName( sName ) )
379 sName = sBaseName + " " + OUString::number(++i);
382 return sName;
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: */