xref: /trunk/main/connectivity/source/drivers/mysql/YDriver.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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