1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 .
21 #include "Catalog.hxx"
23 #include "Connection.hxx"
24 #include "DatabaseMetaData.hxx"
26 #include "PreparedStatement.hxx"
27 #include "Statement.hxx"
32 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/io/XStream.hpp>
35 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
36 #include <com/sun/star/sdbc/SQLException.hpp>
37 #include <com/sun/star/sdbc/XRow.hpp>
38 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
39 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
40 #include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
42 #include <connectivity/dbexception.hxx>
43 #include <strings.hrc>
44 #include <resource/sharedresources.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/servicehelper.hxx>
48 #include <comphelper/storagehelper.hxx>
49 #include <cppuhelper/exc_hlp.hxx>
50 #include <cppuhelper/typeprovider.hxx>
51 #include <unotools/tempfile.hxx>
52 #include <unotools/localfilehelper.hxx>
54 #include <osl/file.hxx>
55 #include <rtl/strbuf.hxx>
56 #include <sal/log.hxx>
58 using namespace connectivity::firebird
;
59 using namespace connectivity
;
61 using namespace ::osl
;
63 using namespace ::com::sun::star
;
64 using namespace ::com::sun::star::beans
;
65 using namespace ::com::sun::star::container
;
66 using namespace ::com::sun::star::document
;
67 using namespace ::com::sun::star::embed
;
68 using namespace ::com::sun::star::io
;
69 using namespace ::com::sun::star::lang
;
70 using namespace ::com::sun::star::sdbc
;
71 using namespace ::com::sun::star::sdbcx
;
72 using namespace ::com::sun::star::uno
;
75 * Location within the .odb that an embedded .fdb will be stored.
76 * Only relevant for embedded dbs.
78 constexpr OUStringLiteral
our_sFDBLocation( u
"firebird.fdb" );
80 * Older version of LO may store the database in a .fdb file
82 constexpr OUStringLiteral
our_sFBKLocation( u
"firebird.fbk" );
84 Connection::Connection()
85 : Connection_BASE(m_aMutex
)
88 , m_bIsEmbedded(false)
90 , m_bIsAutoCommit(true)
91 , m_bIsReadOnly(false)
92 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ
)
93 #if SAL_TYPES_SIZEOFPOINTER == 8
95 , m_aTransactionHandle(0)
97 , m_aDBHandle(nullptr)
98 , m_aTransactionHandle(nullptr)
100 , m_xCatalog(nullptr)
101 , m_xMetaData(nullptr)
106 Connection::~Connection()
114 struct ConnectionGuard
116 oslInterlockedCount
& m_refCount
;
117 explicit ConnectionGuard(oslInterlockedCount
& refCount
)
118 : m_refCount(refCount
)
120 osl_atomic_increment(&m_refCount
);
124 osl_atomic_decrement(&m_refCount
);
130 void Connection::construct(const OUString
& url
, const Sequence
< PropertyValue
>& info
)
132 ConnectionGuard
aGuard(m_refCount
);
136 m_sConnectionURL
= url
;
138 bool bIsNewDatabase
= false;
139 // the database may be stored as an
140 // fdb file in older versions
141 bool bIsFdbStored
= false;
142 if (url
== "sdbc:embedded:firebird")
144 m_bIsEmbedded
= true;
146 const PropertyValue
* pIter
= info
.getConstArray();
147 const PropertyValue
* pEnd
= pIter
+ info
.getLength();
149 for (;pIter
!= pEnd
; ++pIter
)
151 if ( pIter
->Name
== "Storage" )
153 m_xEmbeddedStorage
.set(pIter
->Value
,UNO_QUERY
);
155 else if ( pIter
->Name
== "Document" )
157 pIter
->Value
>>= m_xParentDocument
;
161 if ( !m_xEmbeddedStorage
.is() )
163 ::connectivity::SharedResources aResources
;
164 const OUString sMessage
= aResources
.getResourceString(STR_NO_STORAGE
);
165 ::dbtools::throwGenericSQLException(sMessage
,*this);
168 bIsNewDatabase
= !m_xEmbeddedStorage
->hasElements();
170 m_pDatabaseFileDir
.reset(new ::utl::TempFile(nullptr, true));
171 m_pDatabaseFileDir
->EnableKillingFile();
172 m_sFirebirdURL
= m_pDatabaseFileDir
->GetFileName() + "/firebird.fdb";
173 m_sFBKPath
= m_pDatabaseFileDir
->GetFileName() + "/firebird.fbk";
175 SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL
);
179 if (m_xEmbeddedStorage
->hasByName(our_sFBKLocation
) &&
180 m_xEmbeddedStorage
->isStreamElement(our_sFBKLocation
))
182 SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" );
183 loadDatabaseFile(our_sFBKLocation
, m_sFBKPath
);
185 else if(m_xEmbeddedStorage
->hasByName(our_sFDBLocation
) &&
186 m_xEmbeddedStorage
->isStreamElement(our_sFDBLocation
))
188 SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk");
190 loadDatabaseFile(our_sFDBLocation
, m_sFirebirdURL
);
194 // There might be files which are not firebird databases.
195 // This is not a problem.
196 bIsNewDatabase
= true;
199 // TODO: Get DB properties from XML
202 // External file AND/OR remote connection
203 else if (url
.startsWith("sdbc:firebird:"))
205 m_sFirebirdURL
= url
.copy(OUString("sdbc:firebird:").getLength());
206 if (m_sFirebirdURL
.startsWith("file://"))
209 uno::Reference
< ucb::XSimpleFileAccess
> xFileAccess
=
210 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext());
211 if (!xFileAccess
->exists(m_sFirebirdURL
))
212 bIsNewDatabase
= true;
214 osl::FileBase::getSystemPathFromFileURL(m_sFirebirdURL
, m_sFirebirdURL
);
218 std::string dpbBuffer
;
220 char userName
[256] = "";
221 char userPassword
[256] = "";
223 dpbBuffer
.push_back(isc_dpb_version1
);
224 dpbBuffer
.push_back(isc_dpb_sql_dialect
);
225 dpbBuffer
.push_back(1); // 1 byte long
226 dpbBuffer
.push_back(FIREBIRD_SQL_DIALECT
);
228 // set UTF8 as default character set of the database
229 const char sCharset
[] = "UTF8";
230 dpbBuffer
.push_back(isc_dpb_set_db_charset
);
231 dpbBuffer
.push_back(sizeof(sCharset
) - 1);
232 dpbBuffer
.append(sCharset
);
233 // set UTF8 as default character set of the connection
234 dpbBuffer
.push_back(isc_dpb_lc_ctype
);
235 dpbBuffer
.push_back(sizeof(sCharset
) - 1);
236 dpbBuffer
.append(sCharset
);
238 // Do any more dpbBuffer additions here
240 if (m_bIsEmbedded
|| m_bIsFile
)
242 strcpy(userName
,"sysdba");
243 strcpy(userPassword
,"masterkey");
247 // TODO: parse password from connection string as needed?
250 if (strlen(userName
))
252 int nUsernameLength
= strlen(userName
);
253 dpbBuffer
.push_back(isc_dpb_user_name
);
254 dpbBuffer
.push_back(nUsernameLength
);
255 dpbBuffer
.append(userName
);
258 if (strlen(userPassword
))
260 int nPasswordLength
= strlen(userPassword
);
261 dpbBuffer
.push_back(isc_dpb_password
);
262 dpbBuffer
.push_back(nPasswordLength
);
263 dpbBuffer
.append(userPassword
);
267 ISC_STATUS_ARRAY status
; /* status vector */
269 const OString sFirebirdURL
= OUStringToOString(m_sFirebirdURL
, RTL_TEXTENCODING_UTF8
);
272 aErr
= isc_create_database(status
,
273 sFirebirdURL
.getLength(),
274 sFirebirdURL
.getStr(),
281 evaluateStatusVector(status
, u
"isc_create_database", *this);
286 if (m_bIsEmbedded
&& !bIsFdbStored
) // We need to restore the .fbk first
288 runBackupService(isc_action_svc_restore
);
291 aErr
= isc_attach_database(status
,
292 sFirebirdURL
.getLength(),
293 sFirebirdURL
.getStr(),
299 evaluateStatusVector(status
, u
"isc_attach_database", *this);
303 if (m_bIsEmbedded
) // Add DocumentEventListener to save the .fdb as needed
305 // We need to attach as a document listener in order to be able to store
306 // the temporary db back into the .odb when saving
307 uno::Reference
<XDocumentEventBroadcaster
> xBroadcaster(m_xParentDocument
, UNO_QUERY
);
309 if (xBroadcaster
.is())
310 xBroadcaster
->addDocumentEventListener(this);
315 catch (const Exception
&)
319 catch (const std::exception
&)
323 catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
326 throw std::runtime_error("Generic Firebird::Exception");
330 void Connection::notifyDatabaseModified()
332 if (m_xParentDocument
.is()) // Only true in embedded mode
333 m_xParentDocument
->setModified(true);
336 //----- XServiceInfo ---------------------------------------------------------
337 IMPLEMENT_SERVICE_INFO(Connection
, "com.sun.star.sdbc.drivers.firebird.Connection",
338 "com.sun.star.sdbc.Connection")
340 Reference
< XBlob
> Connection::createBlob(ISC_QUAD
const * pBlobId
)
342 MutexGuard
aGuard(m_aMutex
);
343 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
345 Reference
< XBlob
> xReturn
= new Blob(&m_aDBHandle
,
346 &m_aTransactionHandle
,
349 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
353 Reference
< XClob
> Connection::createClob(ISC_QUAD
const * pBlobId
)
355 MutexGuard
aGuard(m_aMutex
);
356 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
358 Reference
< XClob
> xReturn
= new Clob(&m_aDBHandle
,
359 &m_aTransactionHandle
,
362 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
366 //----- XUnoTunnel ----------------------------------------------------------
368 sal_Int64 SAL_CALL
Connection::getSomething(const css::uno::Sequence
<sal_Int8
>& rId
)
370 return (isUnoTunnelId
<Connection
>(rId
)) ? reinterpret_cast<sal_Int64
>(this) : sal_Int64(0);
374 css::uno::Sequence
<sal_Int8
> Connection::getUnoTunnelId()
376 static const cppu::OImplementationId implId
;
377 return implId
.getImplementationId();
380 //----- XConnection ----------------------------------------------------------
381 Reference
< XStatement
> SAL_CALL
Connection::createStatement( )
383 MutexGuard
aGuard( m_aMutex
);
384 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
387 if(m_aTypeInfo
.empty())
390 // create a statement
391 // the statement can only be executed once
392 Reference
< XStatement
> xReturn
= new OStatement(this);
393 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
397 Reference
< XPreparedStatement
> SAL_CALL
Connection::prepareStatement(
398 const OUString
& _sSql
)
400 SAL_INFO("connectivity.firebird", "prepareStatement() "
401 "called with sql: " << _sSql
);
402 MutexGuard
aGuard(m_aMutex
);
403 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
405 if(m_aTypeInfo
.empty())
408 Reference
< XPreparedStatement
> xReturn
= new OPreparedStatement(this, _sSql
);
409 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
414 Reference
< XPreparedStatement
> SAL_CALL
Connection::prepareCall(
415 const OUString
& _sSql
)
417 SAL_INFO("connectivity.firebird", "prepareCall(). "
420 MutexGuard
aGuard( m_aMutex
);
421 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
423 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
425 // not implemented yet :-) a task to do
429 OUString SAL_CALL
Connection::nativeSQL( const OUString
& _sSql
)
431 MutexGuard
aGuard( m_aMutex
);
432 // We do not need to adapt the SQL for Firebird atm.
436 void SAL_CALL
Connection::setAutoCommit( sal_Bool autoCommit
)
438 MutexGuard
aGuard( m_aMutex
);
439 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
441 m_bIsAutoCommit
= autoCommit
;
443 if (m_aTransactionHandle
)
449 sal_Bool SAL_CALL
Connection::getAutoCommit()
451 MutexGuard
aGuard( m_aMutex
);
452 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
454 return m_bIsAutoCommit
;
457 void Connection::setupTransaction()
459 MutexGuard
aGuard( m_aMutex
);
460 ISC_STATUS status_vector
[20];
462 // TODO: is this sensible? If we have changed parameters then transaction
464 if (m_aTransactionHandle
)
467 isc_rollback_transaction(status_vector
, &m_aTransactionHandle
);
470 char aTransactionIsolation
= 0;
471 switch (m_aTransactionIsolation
)
473 // TODO: confirm that these are correct.
474 case TransactionIsolation::READ_UNCOMMITTED
:
475 aTransactionIsolation
= isc_tpb_concurrency
;
477 case TransactionIsolation::READ_COMMITTED
:
478 aTransactionIsolation
= isc_tpb_read_committed
;
480 case TransactionIsolation::REPEATABLE_READ
:
481 aTransactionIsolation
= isc_tpb_consistency
;
483 case TransactionIsolation::SERIALIZABLE
:
484 aTransactionIsolation
= isc_tpb_consistency
;
487 assert( false ); // We must have a valid TransactionIsolation.
490 // You cannot pass an empty tpb parameter so we have to do some pointer
491 // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
495 *pTPB
++ = isc_tpb_version3
;
497 *pTPB
++ = isc_tpb_autocommit
;
498 *pTPB
++ = (!m_bIsReadOnly
? isc_tpb_write
: isc_tpb_read
);
499 *pTPB
++ = aTransactionIsolation
;
500 *pTPB
++ = isc_tpb_wait
;
502 isc_start_transaction(status_vector
,
503 &m_aTransactionHandle
,
506 pTPB
- aTPB
, // bytes used in TPB
509 evaluateStatusVector(status_vector
,
510 u
"isc_start_transaction",
514 isc_tr_handle
& Connection::getTransaction()
516 MutexGuard
aGuard( m_aMutex
);
517 if (!m_aTransactionHandle
)
521 return m_aTransactionHandle
;
524 void SAL_CALL
Connection::commit()
526 MutexGuard
aGuard( m_aMutex
);
527 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
529 ISC_STATUS status_vector
[20];
531 if (!m_bIsAutoCommit
&& m_aTransactionHandle
)
534 isc_commit_transaction(status_vector
, &m_aTransactionHandle
);
535 evaluateStatusVector(status_vector
,
536 u
"isc_commit_transaction",
541 void Connection::loadDatabaseFile(const OUString
& srcLocation
, const OUString
& tmpLocation
)
543 Reference
< XStream
> xDBStream(m_xEmbeddedStorage
->openStreamElement(srcLocation
,
544 ElementModes::READ
));
546 uno::Reference
< ucb::XSimpleFileAccess2
> xFileAccess
=
547 ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
548 if ( !xFileAccess
.is() )
550 ::connectivity::SharedResources aResources
;
551 // TODO FIXME: this does _not_ look like the right error message
552 const OUString sMessage
= aResources
.getResourceString(STR_ERROR_NEW_VERSION
);
553 ::dbtools::throwGenericSQLException(sMessage
,*this);
555 xFileAccess
->writeFile(tmpLocation
,xDBStream
->getInputStream());
558 isc_svc_handle
Connection::attachServiceManager()
560 ISC_STATUS_ARRAY aStatusVector
;
561 #if SAL_TYPES_SIZEOFPOINTER == 8
562 isc_svc_handle aServiceHandle
= 0;
564 isc_svc_handle aServiceHandle
= nullptr;
567 char aSPBBuffer
[256];
568 char* pSPB
= aSPBBuffer
;
569 *pSPB
++ = isc_spb_version
;
570 *pSPB
++ = isc_spb_current_version
;
571 *pSPB
++ = isc_spb_user_name
;
572 OUString
sUserName("SYSDBA");
573 char aLength
= static_cast<char>(sUserName
.getLength());
576 OUStringToOString(sUserName
,
577 RTL_TEXTENCODING_UTF8
).getStr(),
580 // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ...
581 if (isc_service_attach(aStatusVector
,
582 0, // Denotes null-terminated string next
588 evaluateStatusVector(aStatusVector
,
589 u
"isc_service_attach",
593 return aServiceHandle
;
596 void Connection::detachServiceManager(isc_svc_handle aServiceHandle
)
598 ISC_STATUS_ARRAY aStatusVector
;
599 if (isc_service_detach(aStatusVector
,
602 evaluateStatusVector(aStatusVector
,
603 u
"isc_service_detach",
608 void Connection::runBackupService(const short nAction
)
610 assert(nAction
== isc_action_svc_backup
611 || nAction
== isc_action_svc_restore
);
613 ISC_STATUS_ARRAY aStatusVector
;
615 // convert paths to 8-Bit strings
616 OString sFDBPath
= OUStringToOString(m_sFirebirdURL
, RTL_TEXTENCODING_UTF8
);
617 OString sFBKPath
= OUStringToOString(m_sFBKPath
, RTL_TEXTENCODING_UTF8
);
620 OStringBuffer aRequest
; // byte array
623 aRequest
.append(static_cast<char>(nAction
));
625 aRequest
.append(char(isc_spb_dbname
)); // .fdb
626 sal_uInt16 nFDBLength
= sFDBPath
.getLength();
627 aRequest
.append(static_cast<char>(nFDBLength
& 0xFF)); // least significant byte first
628 aRequest
.append(static_cast<char>((nFDBLength
>> 8) & 0xFF));
629 aRequest
.append(sFDBPath
);
631 aRequest
.append(char(isc_spb_bkp_file
)); // .fbk
632 sal_uInt16 nFBKLength
= sFBKPath
.getLength();
633 aRequest
.append(static_cast<char>(nFBKLength
& 0xFF));
634 aRequest
.append(static_cast<char>((nFBKLength
>> 8) & 0xFF));
635 aRequest
.append(sFBKPath
);
637 if (nAction
== isc_action_svc_restore
)
639 aRequest
.append(char(isc_spb_options
)); // 4-Byte bitmask
641 char * pOptions
= sOptions
;
643 #pragma warning(push)
644 #pragma warning(disable: 4310) // cast truncates data
646 ADD_SPB_NUMERIC(pOptions
, isc_spb_res_create
);
650 aRequest
.append(sOptions
, 4);
653 isc_svc_handle aServiceHandle
;
654 aServiceHandle
= attachServiceManager();
656 if (isc_service_start(aStatusVector
,
659 aRequest
.getLength(),
662 evaluateStatusVector(aStatusVector
, u
"isc_service_start", *this);
665 char aInfoSPB
= isc_info_svc_line
;
668 // query blocks until success or error
669 if(isc_service_query(aStatusVector
,
671 nullptr, // Reserved null
672 0,nullptr, // "send" spb -- size and spb -- not needed?
678 evaluateStatusVector(aStatusVector
, u
"isc_service_query", *this);
681 detachServiceManager(aServiceHandle
);
685 void SAL_CALL
Connection::rollback()
687 MutexGuard
aGuard( m_aMutex
);
688 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
690 ISC_STATUS status_vector
[20];
692 if (!m_bIsAutoCommit
&& m_aTransactionHandle
)
694 isc_rollback_transaction(status_vector
, &m_aTransactionHandle
);
698 sal_Bool SAL_CALL
Connection::isClosed( )
700 MutexGuard
aGuard( m_aMutex
);
702 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
703 return Connection_BASE::rBHelper
.bDisposed
;
706 Reference
< XDatabaseMetaData
> SAL_CALL
Connection::getMetaData( )
708 MutexGuard
aGuard( m_aMutex
);
709 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
711 // here we have to create the class with biggest interface
712 // The answer is 42 :-)
713 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
716 xMetaData
= new ODatabaseMetaData(this); // need the connection because it can return it
717 m_xMetaData
= xMetaData
;
723 void SAL_CALL
Connection::setReadOnly(sal_Bool readOnly
)
725 MutexGuard
aGuard( m_aMutex
);
726 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
728 m_bIsReadOnly
= readOnly
;
732 sal_Bool SAL_CALL
Connection::isReadOnly()
734 MutexGuard
aGuard( m_aMutex
);
735 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
737 return m_bIsReadOnly
;
740 void SAL_CALL
Connection::setCatalog(const OUString
& /*catalog*/)
742 ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this);
745 OUString SAL_CALL
Connection::getCatalog()
747 ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this);
751 void SAL_CALL
Connection::setTransactionIsolation( sal_Int32 level
)
753 MutexGuard
aGuard( m_aMutex
);
754 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
756 m_aTransactionIsolation
= level
;
760 sal_Int32 SAL_CALL
Connection::getTransactionIsolation( )
762 MutexGuard
aGuard( m_aMutex
);
763 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
765 return m_aTransactionIsolation
;
768 Reference
< XNameAccess
> SAL_CALL
Connection::getTypeMap()
770 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
774 void SAL_CALL
Connection::setTypeMap(const Reference
< XNameAccess
>&)
776 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
779 //----- XCloseable -----------------------------------------------------------
780 void SAL_CALL
Connection::close( )
782 // we just dispose us
784 MutexGuard
aGuard( m_aMutex
);
785 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
792 Any SAL_CALL
Connection::getWarnings( )
794 // when you collected some warnings -> return it
798 void SAL_CALL
Connection::clearWarnings( )
800 // you should clear your collected warnings here
803 // XDocumentEventListener
804 void SAL_CALL
Connection::documentEventOccured( const DocumentEvent
& Event
)
806 MutexGuard
aGuard(m_aMutex
);
811 if (Event
.EventName
!= "OnSave" && Event
.EventName
!= "OnSaveAs")
814 commit(); // Commit and close transaction
815 if ( !(m_bIsEmbedded
&& m_xEmbeddedStorage
.is()) )
818 SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
821 runBackupService(isc_action_svc_backup
);
823 catch (const SQLException
& e
)
825 auto a
= cppu::getCaughtException();
826 throw WrappedTargetRuntimeException(e
.Message
, e
.Context
, a
);
830 Reference
< XStream
> xDBStream(m_xEmbeddedStorage
->openStreamElement(our_sFBKLocation
,
831 ElementModes::WRITE
));
833 // TODO: verify the backup actually exists -- the backup service
834 // can fail without giving any sane error messages / telling us
836 using namespace ::comphelper
;
837 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
838 Reference
< XInputStream
> xInputStream
;
843 OStorageHelper::GetInputStreamFromURL(m_sFBKPath
, xContext
);
844 if (xInputStream
.is())
845 OStorageHelper::CopyInputToOutput( xInputStream
,
846 xDBStream
->getOutputStream());
848 // remove old fdb file if exists
849 uno::Reference
< ucb::XSimpleFileAccess
> xFileAccess
=
850 ucb::SimpleFileAccess::create(xContext
);
851 if (xFileAccess
->exists(m_sFirebirdURL
))
852 xFileAccess
->kill(m_sFirebirdURL
);
855 void SAL_CALL
Connection::disposing(const EventObject
& /*rSource*/)
857 MutexGuard
aGuard( m_aMutex
);
859 m_xEmbeddedStorage
.clear();
862 void Connection::buildTypeInfo()
864 MutexGuard
aGuard( m_aMutex
);
866 Reference
< XResultSet
> xRs
= getMetaData ()->getTypeInfo ();
867 Reference
< XRow
> xRow(xRs
,UNO_QUERY
);
868 // Information for a single SQL type
870 // Loop on the result set until we reach end of file
875 aInfo
.aTypeName
= xRow
->getString (1);
876 aInfo
.nType
= xRow
->getShort (2);
877 aInfo
.nPrecision
= xRow
->getInt (3);
878 // aLiteralPrefix = xRow->getString (4);
879 // aLiteralSuffix = xRow->getString (5);
880 // aCreateParams = xRow->getString (6);
881 // bNullable = xRow->getBoolean (7);
882 // bCaseSensitive = xRow->getBoolean (8);
883 // nSearchType = xRow->getShort (9);
884 // bUnsigned = xRow->getBoolean (10);
885 // bCurrency = xRow->getBoolean (11);
886 // bAutoIncrement = xRow->getBoolean (12);
887 aInfo
.aLocalTypeName
= xRow
->getString (13);
888 // nMinimumScale = xRow->getShort (14);
889 aInfo
.nMaximumScale
= xRow
->getShort (15);
890 // nNumPrecRadix = (sal_Int16)xRow->getInt(18);
893 // Now that we have the type info, save it
894 // in the Hashtable if we don't already have an
895 // entry for this SQL type.
897 m_aTypeInfo
.push_back(aInfo
);
900 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
903 // Close the result set/statement.
905 Reference
< XCloseable
> xClose(xRs
,UNO_QUERY
);
908 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
912 void Connection::disposing()
914 MutexGuard
aGuard(m_aMutex
);
918 m_xMetaData
= css::uno::WeakReference
< css::sdbc::XDatabaseMetaData
>();
920 ISC_STATUS_ARRAY status
; /* status vector */
921 if (m_aTransactionHandle
)
923 // TODO: confirm whether we need to ask the user here.
924 isc_rollback_transaction(status
, &m_aTransactionHandle
);
929 if (isc_detach_database(status
, &m_aDBHandle
))
931 evaluateStatusVector(status
, u
"isc_detach_database", *this);
934 // TODO: write to storage again?
936 cppu::WeakComponentImplHelperBase::disposing();
938 if (m_pDatabaseFileDir
)
940 ::utl::removeTree(m_pDatabaseFileDir
->GetURL());
941 m_pDatabaseFileDir
.reset();
945 void Connection::disposeStatements()
947 MutexGuard
aGuard(m_aMutex
);
948 for (auto const& statement
: m_aStatements
)
950 Reference
< XComponent
> xComp(statement
.get(), UNO_QUERY
);
954 m_aStatements
.clear();
957 uno::Reference
< XTablesSupplier
> Connection::createCatalog()
959 MutexGuard
aGuard(m_aMutex
);
961 // m_xCatalog is a weak reference. Reuse it if it still exists.
962 Reference
< XTablesSupplier
> xCatalog
= m_xCatalog
;
969 xCatalog
= new Catalog(this);
970 m_xCatalog
= xCatalog
;
976 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */