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