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