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 #include "mysql/YDriver.hxx" 31 #include "mysql/YCatalog.hxx" 32 #include <osl/diagnose.h> 33 #include <comphelper/namedvaluecollection.hxx> 34 #include "connectivity/dbexception.hxx" 35 #include <connectivity/dbcharset.hxx> 36 #include <com/sun/star/sdbc/XDriverAccess.hpp> 37 #include "TConnection.hxx" 38 #include "resource/common_res.hrc" 39 #include "resource/sharedresources.hxx" 40 41 //........................................................................ 42 namespace connectivity 43 { 44 //........................................................................ 45 using namespace mysql; 46 using namespace ::com::sun::star::uno; 47 using namespace ::com::sun::star::sdbc; 48 using namespace ::com::sun::star::sdbcx; 49 using namespace ::com::sun::star::beans; 50 using namespace ::com::sun::star::lang; 51 52 namespace mysql 53 { 54 Reference< XInterface > SAL_CALL ODriverDelegator_CreateInstance(const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFac) throw( Exception ) 55 { 56 return *(new ODriverDelegator(_rxFac)); 57 } 58 } 59 60 61 //==================================================================== 62 //= ODriverDelegator 63 //==================================================================== 64 //-------------------------------------------------------------------- 65 ODriverDelegator::ODriverDelegator(const Reference< XMultiServiceFactory >& _rxFactory) 66 : ODriverDelegator_BASE(m_aMutex) 67 ,m_xFactory(_rxFactory) 68 ,m_eDriverType(D_ODBC) 69 { 70 } 71 72 //-------------------------------------------------------------------- 73 ODriverDelegator::~ODriverDelegator() 74 { 75 try 76 { 77 ::comphelper::disposeComponent(m_xODBCDriver); 78 ::comphelper::disposeComponent(m_xNativeDriver); 79 TJDBCDrivers::iterator aIter = m_aJdbcDrivers.begin(); 80 TJDBCDrivers::iterator aEnd = m_aJdbcDrivers.end(); 81 for ( ;aIter != aEnd;++aIter ) 82 ::comphelper::disposeComponent(aIter->second); 83 } 84 catch(const Exception&) 85 { 86 } 87 } 88 89 // -------------------------------------------------------------------------------- 90 void ODriverDelegator::disposing() 91 { 92 ::osl::MutexGuard aGuard(m_aMutex); 93 94 95 for (TWeakPairVector::iterator i = m_aConnections.begin(); m_aConnections.end() != i; ++i) 96 { 97 Reference<XInterface > xTemp = i->first.get(); 98 ::comphelper::disposeComponent(xTemp); 99 } 100 m_aConnections.clear(); 101 TWeakPairVector().swap(m_aConnections); 102 103 ODriverDelegator_BASE::disposing(); 104 } 105 106 namespace 107 { 108 sal_Bool isOdbcUrl(const ::rtl::OUString& _sUrl) 109 { 110 return _sUrl.copy(0,16).equalsAscii("sdbc:mysql:odbc:"); 111 } 112 //-------------------------------------------------------------------- 113 sal_Bool isNativeUrl(const ::rtl::OUString& _sUrl) 114 { 115 return (!_sUrl.compareTo(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("sdbc:mysql:mysqlc:")), sizeof("sdbc:mysql:mysqlc:")-1)); 116 } 117 //-------------------------------------------------------------------- 118 T_DRIVERTYPE lcl_getDriverType(const ::rtl::OUString& _sUrl) 119 { 120 T_DRIVERTYPE eRet = D_JDBC; 121 if ( isOdbcUrl(_sUrl ) ) 122 eRet = D_ODBC; 123 else if ( isNativeUrl(_sUrl ) ) 124 eRet = D_NATIVE; 125 return eRet; 126 } 127 //-------------------------------------------------------------------- 128 ::rtl::OUString transformUrl(const ::rtl::OUString& _sUrl) 129 { 130 ::rtl::OUString sNewUrl = _sUrl.copy(11); 131 if ( isOdbcUrl( _sUrl ) ) 132 sNewUrl = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("sdbc:")) + sNewUrl; 133 else if ( isNativeUrl( _sUrl ) ) 134 sNewUrl = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("sdbc:")) + sNewUrl; 135 else 136 { 137 sNewUrl = sNewUrl.copy(5); 138 139 ::rtl::OUString sTempUrl = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("jdbc:mysql://")); 140 141 sTempUrl += sNewUrl; 142 sNewUrl = sTempUrl; 143 } 144 return sNewUrl; 145 } 146 //-------------------------------------------------------------------- 147 Reference< XDriver > lcl_loadDriver(const Reference< XMultiServiceFactory >& _rxFactory,const ::rtl::OUString& _sUrl) 148 { 149 Reference<XDriverAccess> xDriverAccess(_rxFactory->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdbc.DriverManager")) ),UNO_QUERY); 150 OSL_ENSURE(xDriverAccess.is(),"Could not load driver manager!"); 151 Reference< XDriver > xDriver; 152 if ( xDriverAccess.is() ) 153 xDriver = xDriverAccess->getDriverByURL(_sUrl); 154 return xDriver; 155 } 156 //-------------------------------------------------------------------- 157 Sequence< PropertyValue > lcl_convertProperties(T_DRIVERTYPE _eType,const Sequence< PropertyValue >& info,const ::rtl::OUString& _sUrl) 158 { 159 ::std::vector<PropertyValue> aProps; 160 const PropertyValue* pSupported = info.getConstArray(); 161 const PropertyValue* pEnd = pSupported + info.getLength(); 162 163 aProps.reserve(info.getLength() + 5); 164 for (;pSupported != pEnd; ++pSupported) 165 { 166 aProps.push_back( *pSupported ); 167 } 168 169 if ( _eType == D_ODBC ) 170 { 171 aProps.push_back( PropertyValue( 172 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Silent")) 173 ,0 174 ,makeAny(sal_True) 175 ,PropertyState_DIRECT_VALUE) ); 176 aProps.push_back( PropertyValue( 177 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PreventGetVersionColumns")) 178 ,0 179 ,makeAny(sal_True) 180 ,PropertyState_DIRECT_VALUE) ); 181 } 182 else if ( _eType == D_JDBC ) 183 { 184 aProps.push_back( PropertyValue( 185 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("JavaDriverClass")) 186 ,0 187 ,makeAny(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.mysql.jdbc.Driver"))) 188 ,PropertyState_DIRECT_VALUE) ); 189 } 190 else 191 { 192 aProps.push_back( PropertyValue( 193 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PublicConnectionURL")) 194 ,0 195 ,makeAny(_sUrl) 196 ,PropertyState_DIRECT_VALUE) ); 197 } 198 aProps.push_back( PropertyValue( 199 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsAutoRetrievingEnabled")) 200 ,0 201 ,makeAny(sal_True) 202 ,PropertyState_DIRECT_VALUE) ); 203 aProps.push_back( PropertyValue( 204 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AutoRetrievingStatement")) 205 ,0 206 ,makeAny(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SELECT LAST_INSERT_ID()"))) 207 ,PropertyState_DIRECT_VALUE) ); 208 aProps.push_back( PropertyValue( 209 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParameterNameSubstitution")) 210 ,0 211 ,makeAny(sal_True) 212 ,PropertyState_DIRECT_VALUE) ); 213 PropertyValue* pProps = aProps.empty() ? 0 : &aProps[0]; 214 return Sequence< PropertyValue >(pProps, aProps.size()); 215 } 216 } 217 //-------------------------------------------------------------------- 218 Reference< XDriver > ODriverDelegator::loadDriver( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) 219 { 220 Reference< XDriver > xDriver; 221 const ::rtl::OUString sCuttedUrl = transformUrl(url); 222 const T_DRIVERTYPE eType = lcl_getDriverType( url ); 223 if ( eType == D_ODBC ) 224 { 225 if ( !m_xODBCDriver.is() ) 226 m_xODBCDriver = lcl_loadDriver(m_xFactory,sCuttedUrl); 227 xDriver = m_xODBCDriver; 228 } // if ( bIsODBC ) 229 else if ( eType == D_NATIVE ) 230 { 231 if ( !m_xNativeDriver.is() ) 232 m_xNativeDriver = lcl_loadDriver(m_xFactory,sCuttedUrl); 233 xDriver = m_xNativeDriver; 234 } 235 else 236 { 237 ::comphelper::NamedValueCollection aSettings( info ); 238 ::rtl::OUString sDriverClass(RTL_CONSTASCII_USTRINGPARAM("com.mysql.jdbc.Driver")); 239 sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass ); 240 241 TJDBCDrivers::iterator aFind = m_aJdbcDrivers.find(sDriverClass); 242 if ( aFind == m_aJdbcDrivers.end() ) 243 aFind = m_aJdbcDrivers.insert(TJDBCDrivers::value_type(sDriverClass,lcl_loadDriver(m_xFactory,sCuttedUrl))).first; 244 xDriver = aFind->second; 245 } 246 247 return xDriver; 248 } 249 250 //-------------------------------------------------------------------- 251 Reference< XConnection > SAL_CALL ODriverDelegator::connect( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException) 252 { 253 Reference< XConnection > xConnection; 254 if ( acceptsURL(url) ) 255 { 256 Reference< XDriver > xDriver; 257 xDriver = loadDriver(url,info); 258 if ( xDriver.is() ) 259 { 260 ::rtl::OUString sCuttedUrl = transformUrl(url); 261 const T_DRIVERTYPE eType = lcl_getDriverType( url ); 262 Sequence< PropertyValue > aConvertedProperties = lcl_convertProperties(eType,info,url); 263 if ( eType == D_JDBC ) 264 { 265 ::comphelper::NamedValueCollection aSettings( info ); 266 ::rtl::OUString sIanaName = aSettings.getOrDefault( "CharSet", ::rtl::OUString() ); 267 if ( sIanaName.getLength() ) 268 { 269 ::dbtools::OCharsetMap aLookupIanaName; 270 ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.find(sIanaName, ::dbtools::OCharsetMap::IANA()); 271 if (aLookup != aLookupIanaName.end() ) 272 { 273 ::rtl::OUString sAdd; 274 if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() ) 275 { 276 static const ::rtl::OUString s_sCharSetOp(RTL_CONSTASCII_USTRINGPARAM("useUnicode=true&")); 277 if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) ) 278 { 279 sAdd = s_sCharSetOp; 280 } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) ) 281 } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() ) 282 if ( sCuttedUrl.indexOf('?') == -1 ) 283 sCuttedUrl += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("?")); 284 else 285 sCuttedUrl += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("&")); 286 sCuttedUrl += sAdd; 287 sCuttedUrl += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("characterEncoding=")); 288 sCuttedUrl += sIanaName; 289 } 290 } 291 } // if ( !bIsODBC ) 292 293 xConnection = xDriver->connect( sCuttedUrl, aConvertedProperties ); 294 if ( xConnection.is() ) 295 { 296 OMetaConnection* pMetaConnection = NULL; 297 // now we have to set the URL to get the correct answer for metadata()->getURL() 298 Reference< XUnoTunnel> xTunnel(xConnection,UNO_QUERY); 299 if ( xTunnel.is() ) 300 { 301 pMetaConnection = reinterpret_cast<OMetaConnection*>(xTunnel->getSomething( OMetaConnection::getUnoTunnelImplementationId() )); 302 if ( pMetaConnection ) 303 pMetaConnection->setURL(url); 304 } 305 m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xConnection),TWeakConnectionPair(WeakReferenceHelper(),pMetaConnection))); 306 } 307 } 308 } 309 return xConnection; 310 } 311 312 //-------------------------------------------------------------------- 313 sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const ::rtl::OUString& url ) throw (SQLException, RuntimeException) 314 { 315 Sequence< PropertyValue > info; 316 317 sal_Bool bOK = url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:odbc:" ) ) 318 || url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:jdbc:" ) ) 319 || ( url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:mysqlc:" ) ) 320 && loadDriver( url, info ).is() 321 ); 322 return bOK; 323 } 324 325 //-------------------------------------------------------------------- 326 Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const ::rtl::OUString& url, const Sequence< PropertyValue >& /*info*/ ) throw (SQLException, RuntimeException) 327 { 328 ::std::vector< DriverPropertyInfo > aDriverInfo; 329 if ( !acceptsURL(url) ) 330 return Sequence< DriverPropertyInfo >(); 331 332 Sequence< ::rtl::OUString > aBoolean(2); 333 aBoolean[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0")); 334 aBoolean[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("1")); 335 336 337 aDriverInfo.push_back(DriverPropertyInfo( 338 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharSet")) 339 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharSet of the database.")) 340 ,sal_False 341 ,::rtl::OUString() 342 ,Sequence< ::rtl::OUString >()) 343 ); 344 aDriverInfo.push_back(DriverPropertyInfo( 345 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SuppressVersionColumns")) 346 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Display version columns (when available).")) 347 ,sal_False 348 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("0")) 349 ,aBoolean) 350 ); 351 const T_DRIVERTYPE eType = lcl_getDriverType( url ); 352 if ( eType == D_JDBC ) 353 { 354 aDriverInfo.push_back(DriverPropertyInfo( 355 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("JavaDriverClass")) 356 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("The JDBC driver class name.")) 357 ,sal_True 358 ,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.mysql.jdbc.Driver")) 359 ,Sequence< ::rtl::OUString >()) 360 ); 361 } 362 363 return Sequence< DriverPropertyInfo >(&aDriverInfo[0],aDriverInfo.size()); 364 } 365 366 //-------------------------------------------------------------------- 367 sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( ) throw (RuntimeException) 368 { 369 return 1; 370 } 371 372 //-------------------------------------------------------------------- 373 sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( ) throw (RuntimeException) 374 { 375 return 0; 376 } 377 378 //-------------------------------------------------------------------- 379 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection ) throw (SQLException, RuntimeException) 380 { 381 ::osl::MutexGuard aGuard( m_aMutex ); 382 checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); 383 384 Reference< XTablesSupplier > xTab; 385 Reference< XUnoTunnel> xTunnel(connection,UNO_QUERY); 386 if ( xTunnel.is() ) 387 { 388 OMetaConnection* pConnection = reinterpret_cast<OMetaConnection*>(xTunnel->getSomething( OMetaConnection::getUnoTunnelImplementationId() )); 389 if ( pConnection ) 390 { 391 TWeakPairVector::iterator aEnd = m_aConnections.end(); 392 for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i) 393 { 394 if ( i->second.second == pConnection ) 395 { 396 xTab = Reference< XTablesSupplier >(i->second.first.get().get(),UNO_QUERY); 397 if ( !xTab.is() ) 398 { 399 xTab = new OMySQLCatalog(connection); 400 i->second.first = WeakReferenceHelper(xTab); 401 } 402 break; 403 } 404 } 405 } 406 } // if ( xTunnel.is() ) 407 if ( !xTab.is() ) 408 { 409 TWeakPairVector::iterator aEnd = m_aConnections.end(); 410 for (TWeakPairVector::iterator i = m_aConnections.begin(); aEnd != i; ++i) 411 { 412 Reference< XConnection > xTemp(i->first.get(),UNO_QUERY); 413 if ( xTemp == connection ) 414 { 415 xTab = Reference< XTablesSupplier >(i->second.first.get().get(),UNO_QUERY); 416 if ( !xTab.is() ) 417 { 418 xTab = new OMySQLCatalog(connection); 419 i->second.first = WeakReferenceHelper(xTab); 420 } 421 break; 422 } 423 } 424 } 425 return xTab; 426 } 427 428 //-------------------------------------------------------------------- 429 Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw (SQLException, RuntimeException) 430 { 431 if ( ! acceptsURL(url) ) 432 { 433 ::connectivity::SharedResources aResources; 434 const ::rtl::OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); 435 ::dbtools::throwGenericSQLException(sMessage ,*this); 436 } // if ( ! acceptsURL(url) ) 437 438 return getDataDefinitionByConnection(connect(url,info)); 439 } 440 441 // XServiceInfo 442 // -------------------------------------------------------------------------------- 443 //------------------------------------------------------------------------------ 444 rtl::OUString ODriverDelegator::getImplementationName_Static( ) throw(RuntimeException) 445 { 446 return rtl::OUString::createFromAscii("org.openoffice.comp.drivers.MySQL.Driver"); 447 } 448 //------------------------------------------------------------------------------ 449 Sequence< ::rtl::OUString > ODriverDelegator::getSupportedServiceNames_Static( ) throw (RuntimeException) 450 { 451 Sequence< ::rtl::OUString > aSNS( 2 ); 452 aSNS[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdbc.Driver"); 453 aSNS[1] = ::rtl::OUString::createFromAscii("com.sun.star.sdbcx.Driver"); 454 return aSNS; 455 } 456 //------------------------------------------------------------------ 457 ::rtl::OUString SAL_CALL ODriverDelegator::getImplementationName( ) throw(RuntimeException) 458 { 459 return getImplementationName_Static(); 460 } 461 462 //------------------------------------------------------------------ 463 sal_Bool SAL_CALL ODriverDelegator::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException) 464 { 465 Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames()); 466 const ::rtl::OUString* pSupported = aSupported.getConstArray(); 467 const ::rtl::OUString* pEnd = pSupported + aSupported.getLength(); 468 for (;pSupported != pEnd && !pSupported->equals(_rServiceName); ++pSupported) 469 ; 470 471 return pSupported != pEnd; 472 } 473 //------------------------------------------------------------------ 474 Sequence< ::rtl::OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( ) throw(RuntimeException) 475 { 476 return getSupportedServiceNames_Static(); 477 } 478 //------------------------------------------------------------------ 479 //........................................................................ 480 } // namespace connectivity 481 //........................................................................ 482