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