build fix
[LibreOffice.git] / connectivity / source / drivers / firebird / Connection.cxx
blobe26c8a6eeaf8390dd8cfec115dfc6e579090c542
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "Catalog.hxx"
21 #include "Connection.hxx"
22 #include "DatabaseMetaData.hxx"
23 #include "Driver.hxx"
24 #include "PreparedStatement.hxx"
25 #include "Statement.hxx"
26 #include "Tables.hxx"
27 #include "Util.hxx"
29 #include <stdexcept>
31 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
32 #include <com/sun/star/embed/ElementModes.hpp>
33 #include <com/sun/star/frame/Desktop.hpp>
34 #include <com/sun/star/frame/FrameSearchFlag.hpp>
35 #include <com/sun/star/frame/XController.hpp>
36 #include <com/sun/star/frame/XFrame.hpp>
37 #include <com/sun/star/frame/XFrames.hpp>
38 #include <com/sun/star/frame/XModel.hpp>
39 #include <com/sun/star/io/TempFile.hpp>
40 #include <com/sun/star/io/XStream.hpp>
41 #include <com/sun/star/lang/DisposedException.hpp>
42 #include <com/sun/star/lang/EventObject.hpp>
43 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
44 #include <com/sun/star/sdbc/ColumnValue.hpp>
45 #include <com/sun/star/sdbc/XRow.hpp>
46 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
47 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
48 #include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
50 #include <connectivity/dbexception.hxx>
51 #include <connectivity/sqlparse.hxx>
52 #include <resource/common_res.hrc>
53 #include <resource/hsqldb_res.hrc>
54 #include <resource/sharedresources.hxx>
56 #include <comphelper/processfactory.hxx>
57 #include <comphelper/storagehelper.hxx>
58 #include <cppuhelper/exc_hlp.hxx>
59 #include <unotools/tempfile.hxx>
60 #include <unotools/localfilehelper.hxx>
61 #include <unotools/ucbstreamhelper.hxx>
63 #include <rtl/strbuf.hxx>
65 #ifdef _WIN32
66 // for ADD_SPB_NUMERIC
67 #pragma warning(disable: 4310) // cast truncates data
68 #endif
70 using namespace connectivity::firebird;
71 using namespace connectivity;
73 using namespace ::osl;
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::beans;
77 using namespace ::com::sun::star::container;
78 using namespace ::com::sun::star::document;
79 using namespace ::com::sun::star::embed;
80 using namespace ::com::sun::star::frame;
81 using namespace ::com::sun::star::io;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::sdbc;
84 using namespace ::com::sun::star::sdbcx;
85 using namespace ::com::sun::star::uno;
87 /**
88 * Location within the .odb that an embedded .fdb will be stored.
89 * Only relevant for embedded dbs.
91 static const OUStringLiteral our_sFDBLocation( "firebird.fdb" );
92 /**
93 * Older version of LO may store the database in a .fdb file
95 static const OUStringLiteral our_sFBKLocation( "firebird.fbk" );
97 Connection::Connection(FirebirdDriver* _pDriver)
98 : Connection_BASE(m_aMutex)
99 , OSubComponent<Connection, Connection_BASE>(static_cast<cppu::OWeakObject*>(_pDriver), this)
100 , m_xDriver(_pDriver)
101 , m_sConnectionURL()
102 , m_sFirebirdURL()
103 , m_bIsEmbedded(false)
104 , m_xEmbeddedStorage(nullptr)
105 , m_bIsFile(false)
106 , m_bIsAutoCommit(false)
107 , m_bIsReadOnly(false)
108 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
109 #if SAL_TYPES_SIZEOFPOINTER == 8
110 , m_aDBHandle(0)
111 , m_aTransactionHandle(0)
112 #else
113 , m_aDBHandle(nullptr)
114 , m_aTransactionHandle(nullptr)
115 #endif
116 , m_xCatalog(nullptr)
117 , m_xMetaData(nullptr)
118 , m_aStatements()
122 Connection::~Connection()
124 if(!isClosed())
125 close();
128 void SAL_CALL Connection::release() throw()
130 release_ChildImpl();
133 struct ConnectionGuard
135 oslInterlockedCount& m_refCount;
136 explicit ConnectionGuard(oslInterlockedCount& refCount)
137 : m_refCount(refCount)
139 osl_atomic_increment(&m_refCount);
141 ~ConnectionGuard()
143 osl_atomic_decrement(&m_refCount);
147 void Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyValue >& info)
148 throw (SQLException, RuntimeException, std::exception)
150 ConnectionGuard aGuard(m_refCount);
154 m_sConnectionURL = url;
156 bool bIsNewDatabase = false;
157 // the database may be stored as an
158 // fdb file in older versions
159 bool bIsFdbStored = false;
160 OUString aStorageURL;
161 if (url == "sdbc:embedded:firebird")
163 m_bIsEmbedded = true;
165 const PropertyValue* pIter = info.getConstArray();
166 const PropertyValue* pEnd = pIter + info.getLength();
168 for (;pIter != pEnd; ++pIter)
170 if ( pIter->Name == "Storage" )
172 m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY);
174 else if ( pIter->Name == "URL" )
176 pIter->Value >>= aStorageURL;
178 else if ( pIter->Name == "Document" )
180 pIter->Value >>= m_xParentDocument;
184 if ( !m_xEmbeddedStorage.is() )
186 ::connectivity::SharedResources aResources;
187 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
188 ::dbtools::throwGenericSQLException(sMessage ,*this);
191 bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
193 m_pDatabaseFileDir.reset(new ::utl::TempFile(nullptr, true));
194 m_pDatabaseFileDir->EnableKillingFile();
195 m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
196 m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
198 SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL);
200 if (!bIsNewDatabase)
202 if (m_xEmbeddedStorage->hasByName(our_sFBKLocation) &&
203 m_xEmbeddedStorage->isStreamElement(our_sFBKLocation))
205 SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" );
206 loadDatabaseFile(our_sFBKLocation, m_sFBKPath);
208 else if(m_xEmbeddedStorage->hasByName(our_sFDBLocation) &&
209 m_xEmbeddedStorage->isStreamElement(our_sFDBLocation))
211 SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk");
212 bIsFdbStored = true;
213 loadDatabaseFile(our_sFDBLocation, m_sFirebirdURL);
215 else
217 ::connectivity::SharedResources aResources;
218 // TODO FIXME: this does _not_ look like the right error message
219 const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
220 ::dbtools::throwGenericSQLException(sMessage ,*this);
224 // TODO: Get DB properties from XML
227 // External file AND/OR remote connection
228 else if (url.startsWith("sdbc:firebird:"))
230 m_sFirebirdURL = url.copy(OUString("sdbc:firebird:").getLength());
231 if (m_sFirebirdURL.startsWith("file://"))
233 m_bIsFile = true;
234 uno::Reference< ucb::XSimpleFileAccess > xFileAccess(
235 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()),
236 uno::UNO_QUERY);
237 if (!xFileAccess->exists(m_sFirebirdURL))
238 bIsNewDatabase = true;
240 m_sFirebirdURL = m_sFirebirdURL.copy(OUString("file://").getLength());
244 char dpbBuffer[1 + 3 + 257 + 257 + 5 ]; // Expand as needed
245 int dpbLength = 0;
247 char* dpb;
248 char userName[256] = "";
249 char userPassword[256] = "";
251 dpb = dpbBuffer;
252 *dpb++ = isc_dpb_version1;
254 *dpb++ = isc_dpb_sql_dialect;
255 *dpb++ = 1; // 1 byte long
256 *dpb++ = FIREBIRD_SQL_DIALECT;
258 // set UTF8 as default character set
259 const char sCharset[] = "UTF8";
260 *dpb++ = isc_dpb_set_db_charset;
261 int nCharsetLength = sizeof(sCharset) - 1;
262 *dpb++ = (char) nCharsetLength;
263 strcpy(dpb, sCharset);
264 dpb+= nCharsetLength;
266 // Do any more dpbBuffer additions here
268 if (m_bIsEmbedded || m_bIsFile)
270 strcpy(userName,"sysdba");
271 strcpy(userPassword,"masterkey");
273 else
275 // TODO: parse password from connection string as needed?
278 if (strlen(userName))
280 int nUsernameLength = strlen(userName);
281 *dpb++ = isc_dpb_user_name;
282 *dpb++ = (char) nUsernameLength;
283 strcpy(dpb, userName);
284 dpb+= nUsernameLength;
287 if (strlen(userPassword))
289 int nPasswordLength = strlen(userPassword);
290 *dpb++ = isc_dpb_password;
291 *dpb++ = (char) nPasswordLength;
292 strcpy(dpb, userPassword);
293 dpb+= nPasswordLength;
296 dpbLength = dpb - dpbBuffer;
299 ISC_STATUS_ARRAY status; /* status vector */
300 ISC_STATUS aErr;
301 if (bIsNewDatabase)
303 aErr = isc_create_database(status,
304 m_sFirebirdURL.getLength(),
305 OUStringToOString(m_sFirebirdURL,RTL_TEXTENCODING_UTF8).getStr(),
306 &m_aDBHandle,
307 dpbLength,
308 dpbBuffer,
310 if (aErr)
312 evaluateStatusVector(status, "isc_create_database", *this);
315 else
317 if (m_bIsEmbedded && !bIsFdbStored) // We need to restore the .fbk first
319 runBackupService(isc_action_svc_restore);
322 aErr = isc_attach_database(status,
323 m_sFirebirdURL.getLength(),
324 OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8).getStr(),
325 &m_aDBHandle,
326 dpbLength,
327 dpbBuffer);
328 if (aErr)
330 evaluateStatusVector(status, "isc_attach_database", *this);
334 if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed
336 // We need to attach as a document listener in order to be able to store
337 // the temporary db back into the .odb when saving
338 uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY);
340 if (xBroadcaster.is())
341 xBroadcaster->addDocumentEventListener(this);
342 else
343 assert(false);
346 catch (const Exception&)
348 throw;
350 catch (const std::exception&)
352 throw;
354 catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
357 throw std::runtime_error("Generic Firebird::Exception");
361 void Connection::notifyDatabaseModified()
363 if (m_xParentDocument.is()) // Only true in embedded mode
364 m_xParentDocument->setModified(true);
367 //----- XServiceInfo ---------------------------------------------------------
368 IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection",
369 "com.sun.star.sdbc.Connection")
371 Reference< XBlob> Connection::createBlob(ISC_QUAD* pBlobId)
372 throw(SQLException, RuntimeException)
374 MutexGuard aGuard(m_aMutex);
375 checkDisposed(Connection_BASE::rBHelper.bDisposed);
377 Reference< XBlob > xReturn = new Blob(&m_aDBHandle,
378 &m_aTransactionHandle,
379 *pBlobId);
381 m_aStatements.push_back(WeakReferenceHelper(xReturn));
382 return xReturn;
385 Reference< XClob> Connection::createClob(ISC_QUAD* pBlobId)
386 throw(SQLException, RuntimeException)
388 MutexGuard aGuard(m_aMutex);
389 checkDisposed(Connection_BASE::rBHelper.bDisposed);
391 Reference< XClob > xReturn = new Clob(&m_aDBHandle,
392 &m_aTransactionHandle,
393 *pBlobId);
395 m_aStatements.push_back(WeakReferenceHelper(xReturn));
396 return xReturn;
400 //----- XConnection ----------------------------------------------------------
401 Reference< XStatement > SAL_CALL Connection::createStatement( )
402 throw(SQLException, RuntimeException, std::exception)
404 MutexGuard aGuard( m_aMutex );
405 checkDisposed(Connection_BASE::rBHelper.bDisposed);
407 // the pre
408 if(m_aTypeInfo.empty())
409 buildTypeInfo();
411 // create a statement
412 // the statement can only be executed once
413 Reference< XStatement > xReturn = new OStatement(this);
414 m_aStatements.push_back(WeakReferenceHelper(xReturn));
415 return xReturn;
418 OUString Connection::transformPreparedStatement(const OUString& _sSQL)
420 OUString sSqlStatement (_sSQL);
423 OSQLParser aParser( m_xDriver->getContext() );
424 OUString sErrorMessage;
425 OUString sNewSql;
426 OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
427 if(pNode)
428 { // special handling for parameters
429 OSQLParseNode::substituteParameterNames(pNode);
430 pNode->parseNodeToStr( sNewSql, this );
431 delete pNode;
432 sSqlStatement = sNewSql;
435 catch(const Exception&)
437 SAL_WARN("connectivity.firebird", "failed to remove named parameters from '" << _sSQL << "'");
439 return sSqlStatement;
442 Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
443 const OUString& _sSql)
444 throw(SQLException, RuntimeException, std::exception)
446 SAL_INFO("connectivity.firebird", "prepareStatement() "
447 "called with sql: " << _sSql);
448 MutexGuard aGuard(m_aMutex);
449 checkDisposed(Connection_BASE::rBHelper.bDisposed);
451 if(m_aTypeInfo.empty())
452 buildTypeInfo();
454 OUString sSqlStatement (transformPreparedStatement( _sSql ));
456 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,
457 sSqlStatement);
458 m_aStatements.push_back(WeakReferenceHelper(xReturn));
460 return xReturn;
463 Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
464 const OUString& _sSql ) throw(SQLException, RuntimeException, std::exception)
466 SAL_INFO("connectivity.firebird", "prepareCall(). "
467 "_sSql: " << _sSql);
469 MutexGuard aGuard( m_aMutex );
470 checkDisposed(Connection_BASE::rBHelper.bDisposed);
472 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
474 // not implemented yet :-) a task to do
475 return nullptr;
478 OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql )
479 throw(SQLException, RuntimeException, std::exception)
481 MutexGuard aGuard( m_aMutex );
482 // We do not need to adapt the SQL for Firebird atm.
483 return _sSql;
486 void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit )
487 throw(SQLException, RuntimeException, std::exception)
489 MutexGuard aGuard( m_aMutex );
490 checkDisposed(Connection_BASE::rBHelper.bDisposed);
492 m_bIsAutoCommit = autoCommit;
494 if (m_aTransactionHandle)
496 setupTransaction();
500 sal_Bool SAL_CALL Connection::getAutoCommit() throw(SQLException, RuntimeException, std::exception)
502 MutexGuard aGuard( m_aMutex );
503 checkDisposed(Connection_BASE::rBHelper.bDisposed);
505 return m_bIsAutoCommit;
508 void Connection::setupTransaction()
509 throw (SQLException)
511 MutexGuard aGuard( m_aMutex );
512 ISC_STATUS status_vector[20];
514 // TODO: is this sensible? If we have changed parameters then transaction
515 // is lost...
516 if (m_aTransactionHandle)
518 disposeStatements();
519 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
522 char aTransactionIsolation = 0;
523 switch (m_aTransactionIsolation)
525 // TODO: confirm that these are correct.
526 case(TransactionIsolation::READ_UNCOMMITTED):
527 aTransactionIsolation = isc_tpb_concurrency;
528 break;
529 case(TransactionIsolation::READ_COMMITTED):
530 aTransactionIsolation = isc_tpb_read_committed;
531 break;
532 case(TransactionIsolation::REPEATABLE_READ):
533 aTransactionIsolation = isc_tpb_consistency;
534 break;
535 case(TransactionIsolation::SERIALIZABLE):
536 aTransactionIsolation = isc_tpb_consistency;
537 break;
538 default:
539 assert( false ); // We must have a valid TransactionIsolation.
542 // You cannot pass an empty tpb parameter so we have to do some pointer
543 // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
544 char aTPB[5];
545 char* pTPB = aTPB;
547 *pTPB++ = isc_tpb_version3;
548 if (m_bIsAutoCommit)
549 *pTPB++ = isc_tpb_autocommit;
550 *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read);
551 *pTPB++ = aTransactionIsolation;
552 *pTPB++ = isc_tpb_wait;
554 isc_start_transaction(status_vector,
555 &m_aTransactionHandle,
557 &m_aDBHandle,
558 pTPB - aTPB, // bytes used in TPB
559 aTPB);
561 evaluateStatusVector(status_vector,
562 "isc_start_transaction",
563 *this);
566 isc_tr_handle& Connection::getTransaction()
567 throw (SQLException)
569 MutexGuard aGuard( m_aMutex );
570 if (!m_aTransactionHandle)
572 setupTransaction();
574 return m_aTransactionHandle;
577 void SAL_CALL Connection::commit() throw(SQLException, RuntimeException, std::exception)
579 MutexGuard aGuard( m_aMutex );
580 checkDisposed(Connection_BASE::rBHelper.bDisposed);
582 ISC_STATUS status_vector[20];
584 if (!m_bIsAutoCommit && m_aTransactionHandle)
586 disposeStatements();
587 isc_commit_transaction(status_vector, &m_aTransactionHandle);
588 evaluateStatusVector(status_vector,
589 "isc_commit_transaction",
590 *this);
594 void Connection::loadDatabaseFile(const OUString& srcLocation, const OUString& tmpLocation)
596 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(srcLocation,
597 ElementModes::READ));
599 uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess(
600 ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ),
601 uno::UNO_QUERY );
602 if ( !xFileAccess.is() )
604 ::connectivity::SharedResources aResources;
605 // TODO FIXME: this does _not_ look like the right error message
606 const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
607 ::dbtools::throwGenericSQLException(sMessage ,*this);
609 xFileAccess->writeFile(tmpLocation,xDBStream->getInputStream());
612 isc_svc_handle Connection::attachServiceManager()
614 ISC_STATUS_ARRAY aStatusVector;
615 #if SAL_TYPES_SIZEOFPOINTER == 8
616 isc_svc_handle aServiceHandle = 0;
617 #else
618 isc_svc_handle aServiceHandle = nullptr;
619 #endif
621 char aSPBBuffer[256];
622 char* pSPB = aSPBBuffer;
623 *pSPB++ = isc_spb_version;
624 *pSPB++ = isc_spb_current_version;
625 *pSPB++ = isc_spb_user_name;
626 OUString sUserName("SYSDBA");
627 char aLength = (char) sUserName.getLength();
628 *pSPB++ = aLength;
629 strncpy(pSPB,
630 OUStringToOString(sUserName,
631 RTL_TEXTENCODING_UTF8).getStr(),
632 aLength);
633 pSPB += aLength;
634 // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ...
635 if (isc_service_attach(aStatusVector,
636 0, // Denotes null-terminated string next
637 "service_mgr",
638 &aServiceHandle,
639 pSPB - aSPBBuffer,
640 aSPBBuffer))
642 evaluateStatusVector(aStatusVector,
643 "isc_service_attach",
644 *this);
647 return aServiceHandle;
650 void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
652 ISC_STATUS_ARRAY aStatusVector;
653 if (isc_service_detach(aStatusVector,
654 &aServiceHandle))
656 evaluateStatusVector(aStatusVector,
657 "isc_service_detach",
658 *this);
662 void Connection::runBackupService(const short nAction)
664 assert(nAction == isc_action_svc_backup
665 || nAction == isc_action_svc_restore);
667 ISC_STATUS_ARRAY aStatusVector;
669 // convert paths to 8-Bit strings
670 OString sFDBPath = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
671 OString sFBKPath = OUStringToOString(m_sFBKPath, RTL_TEXTENCODING_UTF8);
674 OStringBuffer aRequest; // byte array
677 aRequest.append((char) nAction);
679 aRequest.append((char) isc_spb_dbname); // .fdb
680 sal_uInt16 nFDBLength = sFDBPath.getLength();
681 aRequest.append((char) (nFDBLength & 0xFF)); // least significant byte first
682 aRequest.append((char) ((nFDBLength >> 8) & 0xFF));
683 aRequest.append(sFDBPath);
685 aRequest.append((char) isc_spb_bkp_file); // .fbk
686 sal_uInt16 nFBKLength = sFBKPath.getLength();
687 aRequest.append((char) (nFBKLength & 0xFF));
688 aRequest.append((char) ((nFBKLength >> 8) & 0xFF));
689 aRequest.append(sFBKPath);
691 if (nAction == isc_action_svc_restore)
693 aRequest.append((char) isc_spb_options); // 4-Byte bitmask
694 char sOptions[4];
695 char * pOptions = sOptions;
696 ADD_SPB_NUMERIC(pOptions, isc_spb_res_create);
697 aRequest.append(sOptions, 4);
700 isc_svc_handle aServiceHandle;
701 aServiceHandle = attachServiceManager();
703 if (isc_service_start(aStatusVector,
704 &aServiceHandle,
705 nullptr,
706 aRequest.getLength(),
707 aRequest.getStr()))
709 evaluateStatusVector(aStatusVector, "isc_service_start", *this);
712 char aInfoSPB = isc_info_svc_line;
713 char aResults[256];
715 // query blocks until success or error
716 if(isc_service_query(aStatusVector,
717 &aServiceHandle,
718 nullptr, // Reserved null
719 0,nullptr, // "send" spb -- size and spb -- not needed?
721 &aInfoSPB,
722 sizeof(aResults),
723 aResults))
725 evaluateStatusVector(aStatusVector, "isc_service_query", *this);
728 detachServiceManager(aServiceHandle);
732 void SAL_CALL Connection::rollback() throw(SQLException, RuntimeException, std::exception)
734 MutexGuard aGuard( m_aMutex );
735 checkDisposed(Connection_BASE::rBHelper.bDisposed);
737 ISC_STATUS status_vector[20];
739 if (!m_bIsAutoCommit && m_aTransactionHandle)
741 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
745 sal_Bool SAL_CALL Connection::isClosed( ) throw(SQLException, RuntimeException, std::exception)
747 MutexGuard aGuard( m_aMutex );
749 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
750 return Connection_BASE::rBHelper.bDisposed;
753 Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData( ) throw(SQLException, RuntimeException, std::exception)
755 MutexGuard aGuard( m_aMutex );
756 checkDisposed(Connection_BASE::rBHelper.bDisposed);
758 // here we have to create the class with biggest interface
759 // The answer is 42 :-)
760 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
761 if(!xMetaData.is())
763 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
764 m_xMetaData = xMetaData;
767 return xMetaData;
770 void SAL_CALL Connection::setReadOnly(sal_Bool readOnly)
771 throw(SQLException, RuntimeException, std::exception)
773 MutexGuard aGuard( m_aMutex );
774 checkDisposed(Connection_BASE::rBHelper.bDisposed);
776 m_bIsReadOnly = readOnly;
777 setupTransaction();
780 sal_Bool SAL_CALL Connection::isReadOnly() throw(SQLException, RuntimeException, std::exception)
782 MutexGuard aGuard( m_aMutex );
783 checkDisposed(Connection_BASE::rBHelper.bDisposed);
785 return m_bIsReadOnly;
788 void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/)
789 throw(SQLException, RuntimeException, std::exception)
791 ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this);
794 OUString SAL_CALL Connection::getCatalog()
795 throw(SQLException, RuntimeException, std::exception)
797 ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this);
798 return OUString();
801 void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException, std::exception)
803 MutexGuard aGuard( m_aMutex );
804 checkDisposed(Connection_BASE::rBHelper.bDisposed);
806 m_aTransactionIsolation = level;
807 setupTransaction();
810 sal_Int32 SAL_CALL Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException, std::exception)
812 MutexGuard aGuard( m_aMutex );
813 checkDisposed(Connection_BASE::rBHelper.bDisposed);
815 return m_aTransactionIsolation;
818 Reference< XNameAccess > SAL_CALL Connection::getTypeMap() throw(SQLException, RuntimeException, std::exception)
820 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
821 return nullptr;
824 void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >& typeMap)
825 throw(SQLException, RuntimeException, std::exception)
827 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
828 (void) typeMap;
831 //----- XCloseable -----------------------------------------------------------
832 void SAL_CALL Connection::close( ) throw(SQLException, RuntimeException, std::exception)
834 // we just dispose us
836 MutexGuard aGuard( m_aMutex );
837 checkDisposed(Connection_BASE::rBHelper.bDisposed);
840 dispose();
843 // XWarningsSupplier
844 Any SAL_CALL Connection::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
846 // when you collected some warnings -> return it
847 return Any();
850 void SAL_CALL Connection::clearWarnings( ) throw(SQLException, RuntimeException, std::exception)
852 // you should clear your collected warnings here
855 // XDocumentEventListener
856 void SAL_CALL Connection::documentEventOccured( const DocumentEvent& Event )
857 throw(RuntimeException, std::exception)
859 MutexGuard aGuard(m_aMutex);
861 if (!m_bIsEmbedded)
862 return;
864 if (Event.EventName == "OnSave" || Event.EventName == "OnSaveAs")
866 commit(); // Commit and close transaction
867 if ( m_bIsEmbedded && m_xEmbeddedStorage.is() )
869 SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
872 runBackupService(isc_action_svc_backup);
874 catch (const SQLException& e)
876 auto a = cppu::getCaughtException();
877 throw WrappedTargetRuntimeException(e.Message, e.Context, a);
881 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation,
882 ElementModes::WRITE));
884 // TODO: verify the backup actually exists -- the backup service
885 // can fail without giving any sane error messages / telling us
886 // that it failed.
887 using namespace ::comphelper;
888 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
889 Reference< XInputStream > xInputStream;
890 if (xContext.is())
892 xInputStream =
893 OStorageHelper::GetInputStreamFromURL(m_sFBKPath, xContext);
894 if (xInputStream.is())
895 OStorageHelper::CopyInputToOutput( xInputStream,
896 xDBStream->getOutputStream());
898 // remove old fdb file if exists
899 uno::Reference< ucb::XSimpleFileAccess > xFileAccess(
900 ucb::SimpleFileAccess::create(xContext),
901 uno::UNO_QUERY);
902 if (xFileAccess->exists(m_sFirebirdURL))
903 xFileAccess->kill(m_sFirebirdURL);
909 // XEventListener
910 void SAL_CALL Connection::disposing(const EventObject& /*rSource*/)
911 throw (RuntimeException, std::exception)
913 MutexGuard aGuard( m_aMutex );
915 m_xEmbeddedStorage.clear();
918 void Connection::buildTypeInfo() throw( SQLException)
920 MutexGuard aGuard( m_aMutex );
922 Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
923 Reference< XRow> xRow(xRs,UNO_QUERY);
924 // Information for a single SQL type
926 // Loop on the result set until we reach end of file
928 while (xRs->next ())
930 OTypeInfo aInfo;
931 aInfo.aTypeName = xRow->getString (1);
932 aInfo.nType = xRow->getShort (2);
933 aInfo.nPrecision = xRow->getInt (3);
934 aInfo.aLiteralPrefix = xRow->getString (4);
935 aInfo.aLiteralSuffix = xRow->getString (5);
936 aInfo.aCreateParams = xRow->getString (6);
937 aInfo.bNullable = xRow->getBoolean (7);
938 aInfo.bCaseSensitive = xRow->getBoolean (8);
939 aInfo.nSearchType = xRow->getShort (9);
940 aInfo.bUnsigned = xRow->getBoolean (10);
941 aInfo.bCurrency = xRow->getBoolean (11);
942 aInfo.bAutoIncrement = xRow->getBoolean (12);
943 aInfo.aLocalTypeName = xRow->getString (13);
944 aInfo.nMinimumScale = xRow->getShort (14);
945 aInfo.nMaximumScale = xRow->getShort (15);
946 aInfo.nNumPrecRadix = (sal_Int16)xRow->getInt(18);
949 // Now that we have the type info, save it
950 // in the Hashtable if we don't already have an
951 // entry for this SQL type.
953 m_aTypeInfo.push_back(aInfo);
956 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
957 "Type info built.");
959 // Close the result set/statement.
961 Reference< XCloseable> xClose(xRs,UNO_QUERY);
962 xClose->close();
964 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
965 "Closed.");
968 void Connection::disposing()
970 MutexGuard aGuard(m_aMutex);
972 disposeStatements();
974 m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>();
976 ISC_STATUS_ARRAY status; /* status vector */
977 if (m_aTransactionHandle)
979 // TODO: confirm whether we need to ask the user here.
980 isc_rollback_transaction(status, &m_aTransactionHandle);
983 if (m_aDBHandle)
985 if (isc_detach_database(status, &m_aDBHandle))
987 evaluateStatusVector(status, "isc_detach_database", *this);
990 // TODO: write to storage again?
992 dispose_ChildImpl();
993 cppu::WeakComponentImplHelperBase::disposing();
994 m_xDriver.clear();
996 if (m_pDatabaseFileDir)
998 ::utl::removeTree((m_pDatabaseFileDir)->GetURL());
999 m_pDatabaseFileDir.reset();
1003 void Connection::disposeStatements()
1005 MutexGuard aGuard(m_aMutex);
1006 for (OWeakRefArray::iterator i = m_aStatements.begin(); m_aStatements.end() != i; ++i)
1008 Reference< XComponent > xComp(i->get(), UNO_QUERY);
1009 if (xComp.is())
1010 xComp->dispose();
1012 m_aStatements.clear();
1015 uno::Reference< XTablesSupplier > Connection::createCatalog()
1017 MutexGuard aGuard(m_aMutex);
1019 // m_xCatalog is a weak reference. Reuse it if it still exists.
1020 Reference< XTablesSupplier > xCatalog = m_xCatalog;
1021 if (xCatalog.is())
1023 return xCatalog;
1025 else
1027 xCatalog = new Catalog(this);
1028 m_xCatalog = xCatalog;
1029 return m_xCatalog;