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