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 :
10 : #include "diagnose_ex.h"
11 : #include "MNSProfileDiscover.hxx"
12 : #include "MConnection.hxx"
13 : #include "MDriver.hxx"
14 : #include "MDatabaseMetaData.hxx"
15 : #include "MCatalog.hxx"
16 : #include "MPreparedStatement.hxx"
17 : #include "MorkParser.hxx"
18 :
19 : #include <connectivity/dbcharset.hxx>
20 : #include <connectivity/dbexception.hxx>
21 : #include <connectivity/sqlerror.hxx>
22 :
23 : #include "resource/mork_res.hrc"
24 : #include "resource/common_res.hrc"
25 :
26 : #include <com/sun/star/sdbc/ColumnValue.hpp>
27 : #include <com/sun/star/sdbc/XRow.hpp>
28 : #include <com/sun/star/sdbc/TransactionIsolation.hpp>
29 :
30 : #include <comphelper/officeresourcebundle.hxx>
31 : #include <comphelper/processfactory.hxx>
32 :
33 : using namespace dbtools;
34 :
35 : //------------------------------------------------------------------------------
36 : using namespace com::sun::star::uno;
37 : using namespace com::sun::star::lang;
38 : using namespace com::sun::star::beans;
39 : using namespace com::sun::star::sdbc;
40 : using namespace com::sun::star::sdbcx;
41 : // --------------------------------------------------------------------------------
42 :
43 : namespace connectivity { namespace mork {
44 :
45 : static const int defaultScope = 0x80;
46 :
47 : // -----------------------------------------------------------------------------
48 :
49 3 : OConnection::OConnection(MorkDriver* _pDriver)
50 : :OSubComponent<OConnection, OConnection_BASE>((::cppu::OWeakObject*)_pDriver, this)
51 : ,m_pDriver(_pDriver)
52 3 : ,m_aColumnAlias( _pDriver->getFactory() )
53 : {
54 3 : m_pDriver->acquire();
55 3 : m_pProfileAccess = new ProfileAccess();
56 3 : m_pMork = new MorkParser();
57 3 : }
58 : //-----------------------------------------------------------------------------
59 3 : OConnection::~OConnection()
60 : {
61 1 : acquire();
62 1 : if(!isClosed())
63 0 : close();
64 1 : m_pDriver->release();
65 1 : m_pDriver = NULL;
66 1 : delete m_pProfileAccess;
67 1 : delete m_pMork;
68 2 : }
69 : //-----------------------------------------------------------------------------
70 27 : void SAL_CALL OConnection::release() throw()
71 : {
72 27 : relase_ChildImpl();
73 27 : }
74 : // -----------------------------------------------------------------------------
75 : //-----------------------------------------------------------------------------
76 3 : void OConnection::construct(const ::rtl::OUString& url,const Sequence< PropertyValue >& info) throw(SQLException)
77 : {
78 : (void) info; // avoid warnings
79 : SAL_INFO("connectivity.mork", "=> OConnection::construct()" );
80 : // open file
81 3 : setURL(url);
82 : //
83 : // Skip 'sdbc:mozab: part of URL
84 : //
85 3 : sal_Int32 nLen = url.indexOf(':');
86 3 : nLen = url.indexOf(':',nLen+1);
87 : OSL_ENSURE( url.copy( 0, nLen ) == "sdbc:address", "OConnection::construct: invalid start of the URI - should never have survived XDriver::acceptsURL!" );
88 :
89 3 : OUString aAddrbookURI(url.copy(nLen+1));
90 : // Get Scheme
91 3 : nLen = aAddrbookURI.indexOf(':');
92 3 : OUString aAddrbookScheme;
93 3 : OUString sAdditionalInfo;
94 3 : if ( nLen == -1 )
95 : {
96 : // There isn't any subschema: - but could be just subschema
97 0 : if ( !aAddrbookURI.isEmpty() )
98 : {
99 0 : aAddrbookScheme= aAddrbookURI;
100 : }
101 : else
102 : {
103 : SAL_WARN("connectivity.mork", "No subschema given!!!");
104 0 : throwGenericSQLException( STR_URI_SYNTAX_ERROR, *this );
105 : }
106 : }
107 : else
108 : {
109 3 : aAddrbookScheme = aAddrbookURI.copy(0, nLen);
110 3 : sAdditionalInfo = aAddrbookURI.copy( nLen + 1 );
111 : }
112 :
113 : SAL_INFO("connectivity.mork", "URI = " << aAddrbookURI );
114 : SAL_INFO("connectivity.mork", "Scheme = " << aAddrbookScheme );
115 :
116 3 : OUString path;
117 3 : const OUString UNITTEST_URL = "thunderbird:unittest:";
118 3 : sal_Int32 unittestIndex = url.indexOf(UNITTEST_URL);
119 :
120 : // production?
121 3 : if (unittestIndex == -1)
122 : {
123 0 : OUString defaultProfile = m_pProfileAccess->getDefaultProfile(::com::sun::star::mozilla::MozillaProductType_Thunderbird);
124 0 : path = m_pProfileAccess->getProfilePath(::com::sun::star::mozilla::MozillaProductType_Thunderbird, defaultProfile);
125 : SAL_INFO("connectivity.mork", "DefaultProfile: " << defaultProfile);
126 : SAL_INFO("connectivity.mork", "ProfilePath: " << path);
127 0 : path += rtl::OUString( "/abook.mab" );
128 : }
129 : else
130 : {
131 3 : path = aAddrbookURI.replaceFirst(UNITTEST_URL, "");
132 : }
133 :
134 : SAL_INFO("connectivity.mork", "AdressbookPath: " << path);
135 :
136 3 : rtl::OString strPath = ::rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8 );
137 :
138 : // Open and parse mork file
139 3 : if (!m_pMork->open(strPath.getStr()))
140 : {
141 : SAL_WARN("connectivity.mork", "Can not parse mork file!");
142 0 : throwGenericSQLException( STR_COULD_NOT_LOAD_FILE, *this );
143 : }
144 :
145 : // check that we can retrieve the tables:
146 3 : MorkTableMap *Tables = m_pMork->getTables( defaultScope );
147 3 : MorkTableMap::iterator tableIter;
148 3 : if (Tables)
149 : {
150 : // Iterate all tables
151 6 : for ( tableIter = Tables->begin(); tableIter != Tables->end(); ++tableIter )
152 : {
153 3 : if ( 0 == tableIter->first ) continue;
154 : SAL_INFO("connectivity.mork", "table->first : " << tableIter->first);
155 : }
156 3 : }
157 3 : }
158 :
159 : // XServiceInfo
160 : // --------------------------------------------------------------------------------
161 0 : IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.mork.OConnection", "com.sun.star.sdbc.Connection")
162 :
163 : // --------------------------------------------------------------------------------
164 0 : Reference< XStatement > SAL_CALL OConnection::createStatement( ) throw(SQLException, RuntimeException)
165 : {
166 : SAL_INFO("connectivity.mork", "=> OConnection::createStatement()" );
167 :
168 0 : ::osl::MutexGuard aGuard( m_aMutex );
169 0 : checkDisposed(OConnection_BASE::rBHelper.bDisposed);
170 :
171 : // create a statement
172 : // the statement can only be executed once
173 0 : Reference< XStatement > xReturn = new OStatement(this);
174 0 : m_aStatements.push_back(WeakReferenceHelper(xReturn));
175 0 : return xReturn;
176 : }
177 : // --------------------------------------------------------------------------------
178 2 : Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
179 : {
180 : SAL_INFO("connectivity.mork", "=> OConnection::prepareStatement()" );
181 : SAL_INFO("connectivity.mork", "OConnection::prepareStatement( " << _sSql << " )");
182 :
183 : OSL_UNUSED( _sSql );
184 2 : ::osl::MutexGuard aGuard( m_aMutex );
185 2 : checkDisposed(OConnection_BASE::rBHelper.bDisposed);
186 :
187 : // the pre
188 : // create a statement
189 : // the statement can only be executed more than once
190 2 : OPreparedStatement* pPrepared = new OPreparedStatement(this,_sSql);
191 2 : Reference< XPreparedStatement > xReturn = pPrepared;
192 2 : pPrepared->lateInit();
193 :
194 2 : m_aStatements.push_back(WeakReferenceHelper(xReturn));
195 2 : return xReturn;
196 : }
197 : // --------------------------------------------------------------------------------
198 0 : Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
199 : {
200 : SAL_INFO("connectivity.mork", "=> OConnection::prepareCall()" );
201 : SAL_INFO("connectivity.mork", "sql: " << _sSql);
202 : OSL_UNUSED( _sSql );
203 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::prepareCall", *this );
204 : SAL_INFO("connectivity.mork", "OConnection::prepareCall( " << _sSql << " )");
205 0 : return NULL;
206 : }
207 : // --------------------------------------------------------------------------------
208 0 : ::rtl::OUString SAL_CALL OConnection::nativeSQL( const ::rtl::OUString& _sSql ) throw(SQLException, RuntimeException)
209 : {
210 : SAL_INFO("connectivity.mork", "=> OConnection::nativeSQL()" );
211 : SAL_INFO("connectivity.mork", "sql: " << _sSql);
212 :
213 0 : ::osl::MutexGuard aGuard( m_aMutex );
214 : // when you need to transform SQL92 to you driver specific you can do it here
215 : SAL_INFO("connectivity.mork", "OConnection::nativeSQL(" << _sSql << " )" );
216 :
217 0 : return _sSql;
218 : }
219 : // --------------------------------------------------------------------------------
220 0 : void SAL_CALL OConnection::setAutoCommit( sal_Bool /*autoCommit*/ ) throw(SQLException, RuntimeException)
221 : {
222 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setAutoCommit", *this );
223 0 : }
224 : // --------------------------------------------------------------------------------
225 0 : sal_Bool SAL_CALL OConnection::getAutoCommit( ) throw(SQLException, RuntimeException)
226 : {
227 : // you have to distinguish which if you are in autocommit mode or not
228 : // at normal case true should be fine here
229 :
230 0 : return sal_True;
231 : }
232 : // --------------------------------------------------------------------------------
233 0 : void SAL_CALL OConnection::commit( ) throw(SQLException, RuntimeException)
234 : {
235 : // when you database does support transactions you should commit here
236 0 : }
237 : // --------------------------------------------------------------------------------
238 0 : void SAL_CALL OConnection::rollback( ) throw(SQLException, RuntimeException)
239 : {
240 : // same as commit but for the other case
241 0 : }
242 : // --------------------------------------------------------------------------------
243 1 : sal_Bool SAL_CALL OConnection::isClosed( ) throw(SQLException, RuntimeException)
244 : {
245 1 : ::osl::MutexGuard aGuard( m_aMutex );
246 :
247 : // just simple -> we are close when we are disposed taht means someone called dispose(); (XComponent)
248 1 : return OConnection_BASE::rBHelper.bDisposed;
249 : }
250 : // --------------------------------------------------------------------------------
251 87 : Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) throw(SQLException, RuntimeException)
252 : {
253 : SAL_INFO("connectivity.mork", "=> OConnection::getMetaData()" );
254 :
255 87 : ::osl::MutexGuard aGuard( m_aMutex );
256 87 : checkDisposed(OConnection_BASE::rBHelper.bDisposed);
257 :
258 : // here we have to create the class with biggest interface
259 : // The answer is 42 :-)
260 87 : Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
261 87 : if(!xMetaData.is())
262 : {
263 3 : xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
264 3 : m_xMetaData = xMetaData;
265 : }
266 :
267 87 : return xMetaData;
268 : }
269 : // --------------------------------------------------------------------------------
270 0 : void SAL_CALL OConnection::setReadOnly( sal_Bool /*readOnly*/ ) throw(SQLException, RuntimeException)
271 : {
272 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setReadOnly", *this );
273 0 : }
274 : // --------------------------------------------------------------------------------
275 0 : sal_Bool SAL_CALL OConnection::isReadOnly( ) throw(SQLException, RuntimeException)
276 : {
277 : // return if your connection to readonly
278 0 : return sal_False;
279 : }
280 : // --------------------------------------------------------------------------------
281 0 : void SAL_CALL OConnection::setCatalog( const ::rtl::OUString& /*catalog*/ ) throw(SQLException, RuntimeException)
282 : {
283 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setCatalog", *this );
284 0 : }
285 : // --------------------------------------------------------------------------------
286 0 : ::rtl::OUString SAL_CALL OConnection::getCatalog( ) throw(SQLException, RuntimeException)
287 : {
288 0 : return ::rtl::OUString();
289 : }
290 : // --------------------------------------------------------------------------------
291 0 : void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ ) throw(SQLException, RuntimeException)
292 : {
293 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setTransactionIsolation", *this );
294 0 : }
295 : // --------------------------------------------------------------------------------
296 0 : sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) throw(SQLException, RuntimeException)
297 : {
298 : // please have a look at @see com.sun.star.sdbc.TransactionIsolation
299 0 : return TransactionIsolation::NONE;
300 : }
301 : // --------------------------------------------------------------------------------
302 0 : Reference< ::com::sun::star::container::XNameAccess > SAL_CALL OConnection::getTypeMap( ) throw(SQLException, RuntimeException)
303 : {
304 : // if your driver has special database types you can return it here
305 0 : return NULL;
306 : }
307 : // --------------------------------------------------------------------------------
308 0 : void SAL_CALL OConnection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException)
309 : {
310 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
311 0 : }
312 : // --------------------------------------------------------------------------------
313 : // XCloseable
314 0 : void SAL_CALL OConnection::close( ) throw(SQLException, RuntimeException)
315 : {
316 : // we just dispose us
317 : {
318 0 : ::osl::MutexGuard aGuard( m_aMutex );
319 0 : checkDisposed(OConnection_BASE::rBHelper.bDisposed);
320 :
321 : }
322 0 : dispose();
323 0 : }
324 : // --------------------------------------------------------------------------------
325 : // XWarningsSupplier
326 0 : Any SAL_CALL OConnection::getWarnings( ) throw(SQLException, RuntimeException)
327 : {
328 : // when you collected some warnings -> return it
329 0 : return Any();
330 : }
331 : // --------------------------------------------------------------------------------
332 0 : void SAL_CALL OConnection::clearWarnings( ) throw(SQLException, RuntimeException)
333 : {
334 : // you should clear your collected warnings here
335 0 : }
336 : //------------------------------------------------------------------------------
337 1 : void OConnection::disposing()
338 : {
339 : // we noticed that we should be destroied in near future so we have to dispose our statements
340 1 : ::osl::MutexGuard aGuard(m_aMutex);
341 1 : dispose_ChildImpl();
342 1 : }
343 : // -----------------------------------------------------------------------------
344 :
345 2 : Reference< XTablesSupplier > SAL_CALL OConnection::createCatalog()
346 : {
347 : OSL_TRACE("IN OConnection::createCatalog()" );
348 2 : ::osl::MutexGuard aGuard( m_aMutex );
349 2 : Reference< XTablesSupplier > xTab = m_xCatalog;
350 2 : if(!m_xCatalog.is())
351 : {
352 2 : OCatalog *pCat = new OCatalog(this);
353 2 : xTab = pCat;
354 2 : m_xCatalog = xTab;
355 : }
356 : OSL_TRACE( "\tOUT OConnection::createCatalog()" );
357 2 : return xTab;
358 : }
359 : // -----------------------------------------------------------------------------
360 :
361 : // -----------------------------------------------------------------------------
362 0 : void OConnection::throwSQLException( const ErrorDescriptor& _rError, const Reference< XInterface >& _rxContext )
363 : {
364 0 : if ( _rError.getResId() != 0 )
365 : {
366 : OSL_ENSURE( ( _rError.getErrorCondition() == 0 ),
367 : "OConnection::throwSQLException: unsupported error code combination!" );
368 :
369 0 : ::rtl::OUString sParameter( _rError.getParameter() );
370 0 : if ( !sParameter.isEmpty() )
371 : {
372 0 : const ::rtl::OUString sError( getResources().getResourceStringWithSubstitution(
373 0 : _rError.getResId(),
374 : "$1$", sParameter
375 0 : ) );
376 0 : ::dbtools::throwGenericSQLException( sError, _rxContext );
377 0 : OSL_FAIL( "OConnection::throwSQLException: unreachable (1)!" );
378 : }
379 :
380 0 : throwGenericSQLException( _rError.getResId(), _rxContext );
381 0 : OSL_FAIL( "OConnection::throwSQLException: unreachable (2)!" );
382 : }
383 :
384 0 : if ( _rError.getErrorCondition() != 0 )
385 : {
386 0 : SQLError aErrorHelper( comphelper::getComponentContext(getDriver()->getFactory()) );
387 0 : ::rtl::OUString sParameter( _rError.getParameter() );
388 0 : if ( !sParameter.isEmpty() )
389 0 : aErrorHelper.raiseException( _rError.getErrorCondition(), _rxContext, sParameter );
390 : else
391 0 : aErrorHelper.raiseException( _rError.getErrorCondition(), _rxContext);
392 0 : OSL_FAIL( "OConnection::throwSQLException: unreachable (3)!" );
393 : }
394 :
395 0 : throwGenericSQLException( STR_UNSPECIFIED_ERROR, _rxContext );
396 0 : }
397 :
398 : // -----------------------------------------------------------------------------
399 0 : void OConnection::throwSQLException( const sal_uInt16 _nErrorResourceId, const Reference< XInterface >& _rxContext )
400 : {
401 0 : ErrorDescriptor aError;
402 0 : aError.setResId( _nErrorResourceId );
403 0 : throwSQLException( aError, _rxContext );
404 0 : }
405 :
406 : } } // namespace connectivity::mork
407 :
408 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|