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