1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_connectivity.hxx" 26 27 #include "connectivity/dbmetadata.hxx" 28 #include "connectivity/dbexception.hxx" 29 #include "connectivity/DriversConfig.hxx" 30 #include "resource/common_res.hrc" 31 #include "resource/sharedresources.hxx" 32 33 /** === begin UNO includes === **/ 34 #include <com/sun/star/lang/IllegalArgumentException.hpp> 35 #include <com/sun/star/container/XChild.hpp> 36 #include <com/sun/star/beans/XPropertySet.hpp> 37 #include <com/sun/star/beans/PropertyValue.hpp> 38 #include <com/sun/star/beans/XPropertySetInfo.hpp> 39 #include <com/sun/star/sdb/BooleanComparisonMode.hpp> 40 #include <com/sun/star/sdbc/XDatabaseMetaData2.hpp> 41 #include <com/sun/star/sdbcx/XUsersSupplier.hpp> 42 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> 43 #include <com/sun/star/sdbc/XDriverAccess.hpp> 44 /** === end UNO includes === **/ 45 46 #include <tools/diagnose_ex.h> 47 #include <comphelper/namedvaluecollection.hxx> 48 #include <comphelper/componentcontext.hxx> 49 #include <comphelper/processfactory.hxx> 50 51 #include <boost/optional.hpp> 52 53 //........................................................................ 54 namespace dbtools 55 { 56 //........................................................................ 57 58 /** === begin UNO using === **/ 59 using ::com::sun::star::uno::Reference; 60 using ::com::sun::star::sdbc::XConnection; 61 using ::com::sun::star::sdbc::XConnection; 62 using ::com::sun::star::sdbc::XDatabaseMetaData; 63 using ::com::sun::star::sdbc::XDatabaseMetaData2; 64 using ::com::sun::star::lang::IllegalArgumentException; 65 using ::com::sun::star::uno::Exception; 66 using ::com::sun::star::uno::Any; 67 using ::com::sun::star::container::XChild; 68 using ::com::sun::star::uno::UNO_QUERY_THROW; 69 using ::com::sun::star::beans::XPropertySet; 70 using ::com::sun::star::uno::Sequence; 71 using ::com::sun::star::beans::PropertyValue; 72 using ::com::sun::star::beans::XPropertySetInfo; 73 using ::com::sun::star::uno::UNO_QUERY; 74 using ::com::sun::star::sdbcx::XUsersSupplier; 75 using ::com::sun::star::sdbcx::XDataDefinitionSupplier; 76 using ::com::sun::star::sdbc::XDriverAccess; 77 using ::com::sun::star::uno::UNO_SET_THROW; 78 /** === end UNO using === **/ 79 namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode; 80 81 //==================================================================== 82 //= DatabaseMetaData_Impl 83 //==================================================================== 84 struct DatabaseMetaData_Impl 85 { 86 Reference< XConnection > xConnection; 87 Reference< XDatabaseMetaData > xConnectionMetaData; 88 ::connectivity::DriversConfig aDriverConfig; 89 90 ::boost::optional< ::rtl::OUString > sCachedIdentifierQuoteString; 91 ::boost::optional< ::rtl::OUString > sCachedCatalogSeparator; 92 DatabaseMetaData_Impldbtools::DatabaseMetaData_Impl93 DatabaseMetaData_Impl() 94 :xConnection() 95 ,xConnectionMetaData() 96 ,aDriverConfig( ::comphelper::getProcessServiceFactory() ) 97 ,sCachedIdentifierQuoteString() 98 ,sCachedCatalogSeparator() 99 { 100 } 101 }; 102 103 //-------------------------------------------------------------------- 104 namespace 105 { 106 //................................................................ lcl_construct(DatabaseMetaData_Impl & _metaDataImpl,const Reference<XConnection> & _connection)107 static void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection ) 108 { 109 _metaDataImpl.xConnection = _connection; 110 if ( !_metaDataImpl.xConnection.is() ) 111 return; 112 113 _metaDataImpl.xConnectionMetaData = _connection->getMetaData(); 114 if ( !_metaDataImpl.xConnectionMetaData.is() ) 115 throw IllegalArgumentException(); 116 } 117 118 //................................................................ lcl_checkConnected(const DatabaseMetaData_Impl & _metaDataImpl)119 static void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl ) 120 { 121 if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() ) 122 { 123 ::connectivity::SharedResources aResources; 124 const ::rtl::OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN)); 125 throwSQLException( sError, SQL_CONNECTION_DOES_NOT_EXIST, NULL ); 126 } 127 } 128 129 //................................................................ lcl_getDriverSetting(const sal_Char * _asciiName,const DatabaseMetaData_Impl & _metaData,Any & _out_setting)130 static bool lcl_getDriverSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting ) 131 { 132 lcl_checkConnected( _metaData ); 133 const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() ); 134 if ( !rDriverMetaData.has( _asciiName ) ) 135 return false; 136 _out_setting = rDriverMetaData.get( _asciiName ); 137 return true; 138 } 139 140 //................................................................ lcl_getConnectionSetting(const sal_Char * _asciiName,const DatabaseMetaData_Impl & _metaData,Any & _out_setting)141 static bool lcl_getConnectionSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting ) 142 { 143 try 144 { 145 Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY ); 146 if ( xConnectionAsChild.is() ) 147 { 148 Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW ); 149 Reference< XPropertySet > xDataSourceSettings( 150 xDataSource->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings" ) ) ), 151 UNO_QUERY_THROW ); 152 153 _out_setting = xDataSourceSettings->getPropertyValue( ::rtl::OUString::createFromAscii( _asciiName ) ); 154 } 155 else 156 { 157 Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW ); 158 ::comphelper::NamedValueCollection aSettings( xExtendedMetaData->getConnectionInfo() ); 159 _out_setting = aSettings.get( _asciiName ); 160 return _out_setting.hasValue(); 161 } 162 return true; 163 } 164 catch( const Exception& ) 165 { 166 DBG_UNHANDLED_EXCEPTION(); 167 } 168 return false; 169 } 170 171 //................................................................ lcl_getConnectionStringSetting(const DatabaseMetaData_Impl & _metaData,::boost::optional<::rtl::OUString> & _cachedSetting,::rtl::OUString (SAL_CALL XDatabaseMetaData::* _getter)())172 static const ::rtl::OUString& lcl_getConnectionStringSetting( 173 const DatabaseMetaData_Impl& _metaData, ::boost::optional< ::rtl::OUString >& _cachedSetting, 174 ::rtl::OUString (SAL_CALL XDatabaseMetaData::*_getter)() ) 175 { 176 if ( !_cachedSetting ) 177 { 178 lcl_checkConnected( _metaData ); 179 try 180 { 181 _cachedSetting.reset( (_metaData.xConnectionMetaData.get()->*_getter)() ); 182 } 183 catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } 184 } 185 return *_cachedSetting; 186 } 187 } 188 189 //==================================================================== 190 //= DatabaseMetaData 191 //==================================================================== 192 //-------------------------------------------------------------------- DatabaseMetaData()193 DatabaseMetaData::DatabaseMetaData() 194 :m_pImpl( new DatabaseMetaData_Impl ) 195 { 196 } 197 198 //-------------------------------------------------------------------- DatabaseMetaData(const Reference<XConnection> & _connection)199 DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection ) 200 :m_pImpl( new DatabaseMetaData_Impl ) 201 { 202 lcl_construct( *m_pImpl, _connection ); 203 } 204 205 //-------------------------------------------------------------------- DatabaseMetaData(const DatabaseMetaData & _copyFrom)206 DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom ) 207 :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) ) 208 { 209 } 210 211 //-------------------------------------------------------------------- operator =(const DatabaseMetaData & _copyFrom)212 DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom ) 213 { 214 if ( this == &_copyFrom ) 215 return *this; 216 217 m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) ); 218 return *this; 219 } 220 221 //-------------------------------------------------------------------- ~DatabaseMetaData()222 DatabaseMetaData::~DatabaseMetaData() 223 { 224 } 225 226 //-------------------------------------------------------------------- isConnected() const227 bool DatabaseMetaData::isConnected() const 228 { 229 return m_pImpl->xConnection.is(); 230 } 231 232 //-------------------------------------------------------------------- supportsSubqueriesInFrom() const233 bool DatabaseMetaData::supportsSubqueriesInFrom() const 234 { 235 lcl_checkConnected( *m_pImpl ); 236 237 bool supportsSubQueries = false; 238 try 239 { 240 sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect(); 241 supportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 ); 242 // TODO: is there a better way to determine this? The above is not really true. More precise, 243 // it's a *very* generous heuristics ... 244 } 245 catch( const Exception& ) 246 { 247 DBG_UNHANDLED_EXCEPTION(); 248 } 249 return supportsSubQueries; 250 } 251 252 //-------------------------------------------------------------------- supportsPrimaryKeys() const253 bool DatabaseMetaData::supportsPrimaryKeys() const 254 { 255 lcl_checkConnected( *m_pImpl ); 256 257 bool doesSupportPrimaryKeys = false; 258 try 259 { 260 Any setting; 261 if ( !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) ) 262 || !( setting >>= doesSupportPrimaryKeys ) 263 ) 264 doesSupportPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar(); 265 } 266 catch( const Exception& ) 267 { 268 DBG_UNHANDLED_EXCEPTION(); 269 } 270 return doesSupportPrimaryKeys; 271 } 272 273 //-------------------------------------------------------------------- getIdentifierQuoteString() const274 const ::rtl::OUString& DatabaseMetaData::getIdentifierQuoteString() const 275 { 276 return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString ); 277 } 278 279 //-------------------------------------------------------------------- getCatalogSeparator() const280 const ::rtl::OUString& DatabaseMetaData::getCatalogSeparator() const 281 { 282 return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator ); 283 } 284 285 //-------------------------------------------------------------------- restrictIdentifiersToSQL92() const286 bool DatabaseMetaData::restrictIdentifiersToSQL92() const 287 { 288 lcl_checkConnected( *m_pImpl ); 289 290 bool restrict( false ); 291 Any setting; 292 if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) ) 293 OSL_VERIFY( setting >>= restrict ); 294 return restrict; 295 } 296 297 //-------------------------------------------------------------------- generateASBeforeCorrelationName() const298 bool DatabaseMetaData::generateASBeforeCorrelationName() const 299 { 300 bool doGenerate( true ); 301 Any setting; 302 if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) ) 303 OSL_VERIFY( setting >>= doGenerate ); 304 return doGenerate; 305 } 306 //-------------------------------------------------------------------- shouldEscapeDateTime() const307 bool DatabaseMetaData::shouldEscapeDateTime() const 308 { 309 bool doGenerate( true ); 310 Any setting; 311 if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) ) 312 OSL_VERIFY( setting >>= doGenerate ); 313 return doGenerate; 314 } 315 //-------------------------------------------------------------------- isAutoIncrementPrimaryKey() const316 bool DatabaseMetaData::isAutoIncrementPrimaryKey() const 317 { 318 bool is( true ); 319 Any setting; 320 if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) ) 321 OSL_VERIFY( setting >>= is ); 322 return is; 323 } 324 //-------------------------------------------------------------------- getBooleanComparisonMode() const325 sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const 326 { 327 sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER ); 328 Any setting; 329 if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) ) 330 OSL_VERIFY( setting >>= mode ); 331 return mode; 332 } 333 //-------------------------------------------------------------------- supportsRelations() const334 bool DatabaseMetaData::supportsRelations() const 335 { 336 lcl_checkConnected( *m_pImpl ); 337 bool bSupport = false; 338 try 339 { 340 bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility(); 341 } 342 catch( const Exception& ) 343 { 344 DBG_UNHANDLED_EXCEPTION(); 345 } 346 try 347 { 348 if ( !bSupport ) 349 { 350 const ::rtl::OUString url = m_pImpl->xConnectionMetaData->getURL(); 351 char pMySQL[] = "sdbc:mysql"; 352 bSupport = url.matchAsciiL(pMySQL,(sizeof(pMySQL)/sizeof(pMySQL[0]))-1); 353 } 354 } 355 catch( const Exception& ) 356 { 357 DBG_UNHANDLED_EXCEPTION(); 358 } 359 return bSupport; 360 } 361 362 //-------------------------------------------------------------------- supportsColumnAliasInOrderBy() const363 bool DatabaseMetaData::supportsColumnAliasInOrderBy() const 364 { 365 bool doGenerate( true ); 366 Any setting; 367 if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) ) 368 OSL_VERIFY( setting >>= doGenerate ); 369 return doGenerate; 370 } 371 372 //-------------------------------------------------------------------- supportsUserAdministration(const::comphelper::ComponentContext & _rContext) const373 bool DatabaseMetaData::supportsUserAdministration( const ::comphelper::ComponentContext& _rContext ) const 374 { 375 lcl_checkConnected( *m_pImpl ); 376 377 bool isSupported( false ); 378 try 379 { 380 // find the XUsersSupplier interface 381 // - either directly at the connection 382 Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY ); 383 if ( !xUsersSupp.is() ) 384 { 385 // - or at the driver manager 386 Reference< XDriverAccess > xDriverManager( 387 _rContext.createComponent( "com.sun.star.sdbc.DriverManager" ), UNO_QUERY_THROW ); 388 Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY ); 389 if ( xDriver.is() ) 390 xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY ); 391 } 392 393 isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() ); 394 } 395 catch( const Exception& ) 396 { 397 DBG_UNHANDLED_EXCEPTION(); 398 } 399 return isSupported; 400 } 401 402 //-------------------------------------------------------------------- displayEmptyTableFolders() const403 bool DatabaseMetaData::displayEmptyTableFolders() const 404 { 405 bool doDisplay( true ); 406 #ifdef IMPLEMENTED_LATER 407 Any setting; 408 if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) ) 409 OSL_VERIFY( setting >>= doDisplay ); 410 #else 411 try 412 { 413 Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW ); 414 ::rtl::OUString sConnectionURL( xMeta->getURL() ); 415 doDisplay = sConnectionURL.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:mysqlc" ) ) == 0; 416 } 417 catch( const Exception& ) 418 { 419 DBG_UNHANDLED_EXCEPTION(); 420 } 421 #endif 422 return doDisplay; 423 } 424 //-------------------------------------------------------------------- supportsThreads() const425 bool DatabaseMetaData::supportsThreads() const 426 { 427 bool bSupported( true ); 428 try 429 { 430 Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW ); 431 ::rtl::OUString sConnectionURL( xMeta->getURL() ); 432 bSupported = sConnectionURL.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:mysqlc" ) ) != 0; 433 } 434 catch( const Exception& ) 435 { 436 DBG_UNHANDLED_EXCEPTION(); 437 } 438 return bSupported; 439 } 440 441 //........................................................................ 442 } // namespace dbtools 443 //........................................................................ 444 445