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