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