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