Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / connectivity / source / drivers / firebird / Connection.cxx
blob5b8cdb7b16d6326550be9327e64ccde020eb983b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 "Blob.hxx"
21 #include "Catalog.hxx"
22 #include "Clob.hxx"
23 #include "Connection.hxx"
24 #include "DatabaseMetaData.hxx"
25 #include "PreparedStatement.hxx"
26 #include "Statement.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/io/XStream.hpp>
34 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
35 #include <com/sun/star/sdbc/SQLException.hpp>
36 #include <com/sun/star/sdbc/XRow.hpp>
37 #include <com/sun/star/sdbc/TransactionIsolation.hpp>
38 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
39 #include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
41 #include <connectivity/dbexception.hxx>
42 #include <strings.hrc>
43 #include <resource/sharedresources.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/servicehelper.hxx>
47 #include <comphelper/storagehelper.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <unotools/tempfile.hxx>
51 #include <osl/file.hxx>
52 #include <rtl/strbuf.hxx>
53 #include <sal/log.hxx>
55 using namespace connectivity::firebird;
56 using namespace connectivity;
58 using namespace ::osl;
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::container;
63 using namespace ::com::sun::star::document;
64 using namespace ::com::sun::star::embed;
65 using namespace ::com::sun::star::io;
66 using namespace ::com::sun::star::lang;
67 using namespace ::com::sun::star::sdbc;
68 using namespace ::com::sun::star::sdbcx;
69 using namespace ::com::sun::star::uno;
71 /**
72 * Location within the .odb that an embedded .fdb will be stored.
73 * Only relevant for embedded dbs.
75 constexpr OUStringLiteral our_sFDBLocation( u"firebird.fdb" );
76 /**
77 * Older version of LO may store the database in a .fdb file
79 constexpr OUStringLiteral our_sFBKLocation( u"firebird.fbk" );
81 Connection::Connection()
82 : Connection_BASE(m_aMutex)
83 , m_bIsEmbedded(false)
84 , m_bIsFile(false)
85 , m_bIsAutoCommit(true)
86 , m_bIsReadOnly(false)
87 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
88 #if SAL_TYPES_SIZEOFPOINTER == 8
89 , m_aDBHandle(0)
90 , m_aTransactionHandle(0)
91 #else
92 , m_aDBHandle(nullptr)
93 , m_aTransactionHandle(nullptr)
94 #endif
95 , m_xCatalog(nullptr)
96 , m_xMetaData(nullptr)
100 Connection::~Connection()
102 if(!isClosed())
103 close();
106 namespace {
108 struct ConnectionGuard
110 oslInterlockedCount& m_refCount;
111 explicit ConnectionGuard(oslInterlockedCount& refCount)
112 : m_refCount(refCount)
114 osl_atomic_increment(&m_refCount);
116 ~ConnectionGuard()
118 osl_atomic_decrement(&m_refCount);
124 void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info)
126 ConnectionGuard aGuard(m_refCount);
130 m_sConnectionURL = url;
132 bool bIsNewDatabase = false;
133 // the database may be stored as an
134 // fdb file in older versions
135 bool bIsFdbStored = false;
136 if (url == "sdbc:embedded:firebird")
138 m_bIsEmbedded = true;
140 const PropertyValue* pIter = info.getConstArray();
141 const PropertyValue* pEnd = pIter + info.getLength();
143 for (;pIter != pEnd; ++pIter)
145 if ( pIter->Name == "Storage" )
147 m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY);
149 else if ( pIter->Name == "Document" )
151 pIter->Value >>= m_xParentDocument;
155 if ( !m_xEmbeddedStorage.is() )
157 ::connectivity::SharedResources aResources;
158 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
159 ::dbtools::throwGenericSQLException(sMessage ,*this);
162 bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
164 m_pDatabaseFileDir.reset(new ::utl::TempFileNamed(nullptr, true));
165 m_pDatabaseFileDir->EnableKillingFile();
166 m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
167 m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
169 SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL);
171 if (!bIsNewDatabase)
173 if (m_xEmbeddedStorage->hasByName(our_sFBKLocation) &&
174 m_xEmbeddedStorage->isStreamElement(our_sFBKLocation))
176 SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" );
177 loadDatabaseFile(our_sFBKLocation, m_sFBKPath);
179 else if(m_xEmbeddedStorage->hasByName(our_sFDBLocation) &&
180 m_xEmbeddedStorage->isStreamElement(our_sFDBLocation))
182 SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk");
183 bIsFdbStored = true;
184 loadDatabaseFile(our_sFDBLocation, m_sFirebirdURL);
186 else
188 // There might be files which are not firebird databases.
189 // This is not a problem.
190 bIsNewDatabase = true;
193 // TODO: Get DB properties from XML
196 // External file AND/OR remote connection
197 else if (url.startsWith("sdbc:firebird:"))
199 m_sFirebirdURL = url.copy(strlen("sdbc:firebird:"));
200 if (m_sFirebirdURL.startsWith("file://"))
202 m_bIsFile = true;
203 uno::Reference< ucb::XSimpleFileAccess > xFileAccess =
204 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext());
205 if (!xFileAccess->exists(m_sFirebirdURL))
206 bIsNewDatabase = true;
208 osl::FileBase::getSystemPathFromFileURL(m_sFirebirdURL, m_sFirebirdURL);
212 std::string dpbBuffer;
214 OString userName;
215 OString userPassword;
217 dpbBuffer.push_back(isc_dpb_version1);
218 dpbBuffer.push_back(isc_dpb_sql_dialect);
219 dpbBuffer.push_back(1); // 1 byte long
220 dpbBuffer.push_back(SQL_DIALECT_CURRENT);
222 // set UTF8 as default character set of the database
223 const char sCharset[] = "UTF8";
224 dpbBuffer.push_back(isc_dpb_set_db_charset);
225 dpbBuffer.push_back(sizeof(sCharset) - 1);
226 dpbBuffer.append(sCharset);
227 // set UTF8 as default character set of the connection
228 dpbBuffer.push_back(isc_dpb_lc_ctype);
229 dpbBuffer.push_back(sizeof(sCharset) - 1);
230 dpbBuffer.append(sCharset);
232 // Do any more dpbBuffer additions here
234 if (m_bIsEmbedded || m_bIsFile)
236 userName = "sysdba";
237 userPassword = "masterkey";
239 else
241 for (const auto& rIter : info)
243 if (rIter.Name == "user")
245 if (OUString value; rIter.Value >>= value)
246 userName = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
248 else if (rIter.Name == "password")
250 if (OUString value; rIter.Value >>= value)
251 userPassword = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
256 if (!userName.isEmpty())
258 const sal_Int32 nMaxUsername = 255; //max size
259 int nUsernameLength = std::min(userName.getLength(), nMaxUsername);
260 dpbBuffer.push_back(isc_dpb_user_name);
261 dpbBuffer.push_back(nUsernameLength);
262 dpbBuffer.append(userName.getStr(), nUsernameLength);
265 if (!userPassword.isEmpty())
267 const sal_Int32 nMaxPassword = 255; //max size
268 int nPasswordLength = std::min(userPassword.getLength(), nMaxPassword);
269 dpbBuffer.push_back(isc_dpb_password);
270 dpbBuffer.push_back(nPasswordLength);
271 dpbBuffer.append(userPassword.getStr(), nPasswordLength);
275 // use isc_dpb_utf8_filename to identify encoding of filenames
276 dpbBuffer.push_back(isc_dpb_utf8_filename);
277 dpbBuffer.push_back(0); // no filename here, it is passed to functions directly
279 ISC_STATUS_ARRAY status; /* status vector */
280 ISC_STATUS aErr;
281 const OString sFirebirdURL = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
282 if (bIsNewDatabase)
284 aErr = isc_create_database(status,
285 sFirebirdURL.getLength(),
286 sFirebirdURL.getStr(),
287 &m_aDBHandle,
288 dpbBuffer.size(),
289 dpbBuffer.c_str(),
291 if (aErr)
293 evaluateStatusVector(status, u"isc_create_database", *this);
296 else
298 if (m_bIsEmbedded && !bIsFdbStored) // We need to restore the .fbk first
300 runBackupService(isc_action_svc_restore);
303 aErr = isc_attach_database(status,
304 sFirebirdURL.getLength(),
305 sFirebirdURL.getStr(),
306 &m_aDBHandle,
307 dpbBuffer.size(),
308 dpbBuffer.c_str());
309 if (aErr)
311 evaluateStatusVector(status, u"isc_attach_database", *this);
315 if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed
317 // We need to attach as a document listener in order to be able to store
318 // the temporary db back into the .odb when saving
319 uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY);
321 if (xBroadcaster.is())
322 xBroadcaster->addDocumentEventListener(this);
323 else
324 assert(false);
327 catch (const Exception&)
329 throw;
331 catch (const std::exception&)
333 throw;
335 catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
338 throw std::runtime_error("Generic Firebird::Exception");
342 void Connection::notifyDatabaseModified()
344 if (m_xParentDocument.is()) // Only true in embedded mode
345 m_xParentDocument->setModified(true);
348 //----- XServiceInfo ---------------------------------------------------------
349 IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection",
350 "com.sun.star.sdbc.Connection")
352 Reference< XBlob> Connection::createBlob(ISC_QUAD const * pBlobId)
354 MutexGuard aGuard(m_aMutex);
355 checkDisposed(Connection_BASE::rBHelper.bDisposed);
357 Reference< XBlob > xReturn = new Blob(&m_aDBHandle,
358 &m_aTransactionHandle,
359 *pBlobId);
361 m_aStatements.push_back(WeakReferenceHelper(xReturn));
362 return xReturn;
365 Reference< XClob> Connection::createClob(ISC_QUAD const * pBlobId)
367 MutexGuard aGuard(m_aMutex);
368 checkDisposed(Connection_BASE::rBHelper.bDisposed);
370 Reference< XClob > xReturn = new Clob(&m_aDBHandle,
371 &m_aTransactionHandle,
372 *pBlobId);
374 m_aStatements.push_back(WeakReferenceHelper(xReturn));
375 return xReturn;
378 //----- XUnoTunnel ----------------------------------------------------------
379 // virtual
380 sal_Int64 SAL_CALL Connection::getSomething(const css::uno::Sequence<sal_Int8>& rId)
382 return comphelper::getSomethingImpl(rId, this);
385 // static
386 const css::uno::Sequence<sal_Int8> & Connection::getUnoTunnelId()
388 static const comphelper::UnoIdInit implId;
389 return implId.getSeq();
392 //----- XConnection ----------------------------------------------------------
393 Reference< XStatement > SAL_CALL Connection::createStatement( )
395 MutexGuard aGuard( m_aMutex );
396 checkDisposed(Connection_BASE::rBHelper.bDisposed);
398 // the pre
399 if(m_aTypeInfo.empty())
400 buildTypeInfo();
402 // create a statement
403 // the statement can only be executed once
404 Reference< XStatement > xReturn = new OStatement(this);
405 m_aStatements.push_back(WeakReferenceHelper(xReturn));
406 return xReturn;
409 Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
410 const OUString& _sSql)
412 SAL_INFO("connectivity.firebird", "prepareStatement() "
413 "called with sql: " << _sSql);
414 MutexGuard aGuard(m_aMutex);
415 checkDisposed(Connection_BASE::rBHelper.bDisposed);
417 if(m_aTypeInfo.empty())
418 buildTypeInfo();
420 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql);
421 m_aStatements.push_back(WeakReferenceHelper(xReturn));
423 return xReturn;
426 Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
427 const OUString& _sSql )
429 SAL_INFO("connectivity.firebird", "prepareCall(). "
430 "_sSql: " << _sSql);
432 MutexGuard aGuard( m_aMutex );
433 checkDisposed(Connection_BASE::rBHelper.bDisposed);
435 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
437 // not implemented yet :-) a task to do
438 return nullptr;
441 OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql )
443 // We do not need to adapt the SQL for Firebird atm.
444 return _sSql;
447 void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit )
449 MutexGuard aGuard( m_aMutex );
450 checkDisposed(Connection_BASE::rBHelper.bDisposed);
452 m_bIsAutoCommit = autoCommit;
454 if (m_aTransactionHandle)
456 setupTransaction();
460 sal_Bool SAL_CALL Connection::getAutoCommit()
462 MutexGuard aGuard( m_aMutex );
463 checkDisposed(Connection_BASE::rBHelper.bDisposed);
465 return m_bIsAutoCommit;
468 void Connection::setupTransaction()
470 MutexGuard aGuard( m_aMutex );
471 ISC_STATUS status_vector[20];
473 // TODO: is this sensible? If we have changed parameters then transaction
474 // is lost...
475 if (m_aTransactionHandle)
477 disposeStatements();
478 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
481 char aTransactionIsolation = 0;
482 switch (m_aTransactionIsolation)
484 // TODO: confirm that these are correct.
485 case TransactionIsolation::READ_UNCOMMITTED:
486 aTransactionIsolation = isc_tpb_concurrency;
487 break;
488 case TransactionIsolation::READ_COMMITTED:
489 aTransactionIsolation = isc_tpb_read_committed;
490 break;
491 case TransactionIsolation::REPEATABLE_READ:
492 aTransactionIsolation = isc_tpb_consistency;
493 break;
494 case TransactionIsolation::SERIALIZABLE:
495 aTransactionIsolation = isc_tpb_consistency;
496 break;
497 default:
498 assert( false ); // We must have a valid TransactionIsolation.
501 // You cannot pass an empty tpb parameter so we have to do some pointer
502 // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
503 char aTPB[5];
504 char* pTPB = aTPB;
506 *pTPB++ = isc_tpb_version3;
507 if (m_bIsAutoCommit)
508 *pTPB++ = isc_tpb_autocommit;
509 *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read);
510 *pTPB++ = aTransactionIsolation;
511 *pTPB++ = isc_tpb_wait;
513 isc_start_transaction(status_vector,
514 &m_aTransactionHandle,
516 &m_aDBHandle,
517 pTPB - aTPB, // bytes used in TPB
518 aTPB);
520 evaluateStatusVector(status_vector,
521 u"isc_start_transaction",
522 *this);
525 isc_tr_handle& Connection::getTransaction()
527 MutexGuard aGuard( m_aMutex );
528 if (!m_aTransactionHandle)
530 setupTransaction();
532 return m_aTransactionHandle;
535 void SAL_CALL Connection::commit()
537 MutexGuard aGuard( m_aMutex );
538 checkDisposed(Connection_BASE::rBHelper.bDisposed);
540 ISC_STATUS status_vector[20];
542 if (!m_bIsAutoCommit && m_aTransactionHandle)
544 disposeStatements();
545 isc_commit_transaction(status_vector, &m_aTransactionHandle);
546 evaluateStatusVector(status_vector,
547 u"isc_commit_transaction",
548 *this);
552 void Connection::loadDatabaseFile(const OUString& srcLocation, const OUString& tmpLocation)
554 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(srcLocation,
555 ElementModes::READ));
557 uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess =
558 ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
559 if ( !xFileAccess.is() )
561 ::connectivity::SharedResources aResources;
562 // TODO FIXME: this does _not_ look like the right error message
563 const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
564 ::dbtools::throwGenericSQLException(sMessage ,*this);
566 xFileAccess->writeFile(tmpLocation,xDBStream->getInputStream());
569 isc_svc_handle Connection::attachServiceManager()
571 ISC_STATUS_ARRAY aStatusVector;
572 #if SAL_TYPES_SIZEOFPOINTER == 8
573 isc_svc_handle aServiceHandle = 0;
574 #else
575 isc_svc_handle aServiceHandle = nullptr;
576 #endif
578 char aSPBBuffer[256];
579 char* pSPB = aSPBBuffer;
580 *pSPB++ = isc_spb_version;
581 *pSPB++ = isc_spb_current_version;
582 *pSPB++ = isc_spb_user_name;
583 OUString sUserName("SYSDBA");
584 char aLength = static_cast<char>(sUserName.getLength());
585 *pSPB++ = aLength;
586 strncpy(pSPB,
587 OUStringToOString(sUserName,
588 RTL_TEXTENCODING_UTF8).getStr(),
589 aLength);
590 pSPB += aLength;
591 // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ...
592 if (isc_service_attach(aStatusVector,
593 0, // Denotes null-terminated string next
594 "service_mgr",
595 &aServiceHandle,
596 pSPB - aSPBBuffer,
597 aSPBBuffer))
599 evaluateStatusVector(aStatusVector,
600 u"isc_service_attach",
601 *this);
604 return aServiceHandle;
607 void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
609 ISC_STATUS_ARRAY aStatusVector;
610 if (isc_service_detach(aStatusVector,
611 &aServiceHandle))
613 evaluateStatusVector(aStatusVector,
614 u"isc_service_detach",
615 *this);
619 void Connection::runBackupService(const short nAction)
621 assert(nAction == isc_action_svc_backup
622 || nAction == isc_action_svc_restore);
624 ISC_STATUS_ARRAY aStatusVector;
626 // convert paths to 8-Bit strings
627 OString sFDBPath = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
628 OString sFBKPath = OUStringToOString(m_sFBKPath, RTL_TEXTENCODING_UTF8);
631 sal_uInt16 nFDBLength = sFDBPath.getLength();
632 sal_uInt16 nFBKLength = sFBKPath.getLength();
633 OStringBuffer aRequest( // byte array
634 OStringChar(static_cast<char>(nAction))
635 + OStringChar(char(isc_spb_dbname)) // .fdb
636 + OStringChar(static_cast<char>(nFDBLength & 0xFF)) // least significant byte first
637 + OStringChar(static_cast<char>((nFDBLength >> 8) & 0xFF))
638 + sFDBPath
639 + OStringChar(char(isc_spb_bkp_file)) // .fbk
640 + OStringChar(static_cast<char>(nFBKLength & 0xFF))
641 + OStringChar(static_cast<char>((nFBKLength >> 8) & 0xFF))
642 + sFBKPath);
644 if (nAction == isc_action_svc_restore)
646 aRequest.append(char(isc_spb_options)); // 4-Byte bitmask
647 char sOptions[4];
648 char * pOptions = sOptions;
649 #ifdef _WIN32
650 #pragma warning(push)
651 #pragma warning(disable: 4310) // cast truncates data
652 #endif
653 ADD_SPB_NUMERIC(pOptions, isc_spb_res_create);
654 #ifdef _WIN32
655 #pragma warning(pop)
656 #endif
657 aRequest.append(sOptions, 4);
660 isc_svc_handle aServiceHandle;
661 aServiceHandle = attachServiceManager();
663 if (isc_service_start(aStatusVector,
664 &aServiceHandle,
665 nullptr,
666 aRequest.getLength(),
667 aRequest.getStr()))
669 evaluateStatusVector(aStatusVector, u"isc_service_start", *this);
672 char aInfoSPB = isc_info_svc_line;
673 char aResults[256];
675 // query blocks until success or error
676 if(isc_service_query(aStatusVector,
677 &aServiceHandle,
678 nullptr, // Reserved null
679 0,nullptr, // "send" spb -- size and spb -- not needed?
681 &aInfoSPB,
682 sizeof(aResults),
683 aResults))
685 evaluateStatusVector(aStatusVector, u"isc_service_query", *this);
688 detachServiceManager(aServiceHandle);
692 void SAL_CALL Connection::rollback()
694 MutexGuard aGuard( m_aMutex );
695 checkDisposed(Connection_BASE::rBHelper.bDisposed);
697 ISC_STATUS status_vector[20];
699 if (!m_bIsAutoCommit && m_aTransactionHandle)
701 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
705 sal_Bool SAL_CALL Connection::isClosed( )
707 MutexGuard aGuard( m_aMutex );
709 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
710 return Connection_BASE::rBHelper.bDisposed;
713 Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData( )
715 MutexGuard aGuard( m_aMutex );
716 checkDisposed(Connection_BASE::rBHelper.bDisposed);
718 // here we have to create the class with biggest interface
719 // The answer is 42 :-)
720 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
721 if(!xMetaData.is())
723 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
724 m_xMetaData = xMetaData;
727 return xMetaData;
730 void SAL_CALL Connection::setReadOnly(sal_Bool readOnly)
732 MutexGuard aGuard( m_aMutex );
733 checkDisposed(Connection_BASE::rBHelper.bDisposed);
735 m_bIsReadOnly = readOnly;
736 setupTransaction();
739 sal_Bool SAL_CALL Connection::isReadOnly()
741 MutexGuard aGuard( m_aMutex );
742 checkDisposed(Connection_BASE::rBHelper.bDisposed);
744 return m_bIsReadOnly;
747 void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/)
749 ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this);
752 OUString SAL_CALL Connection::getCatalog()
754 ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this);
755 return OUString();
758 void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level )
760 MutexGuard aGuard( m_aMutex );
761 checkDisposed(Connection_BASE::rBHelper.bDisposed);
763 m_aTransactionIsolation = level;
764 setupTransaction();
767 sal_Int32 SAL_CALL Connection::getTransactionIsolation( )
769 MutexGuard aGuard( m_aMutex );
770 checkDisposed(Connection_BASE::rBHelper.bDisposed);
772 return m_aTransactionIsolation;
775 Reference< XNameAccess > SAL_CALL Connection::getTypeMap()
777 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
778 return nullptr;
781 void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >&)
783 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
786 //----- XCloseable -----------------------------------------------------------
787 void SAL_CALL Connection::close( )
789 // we just dispose us
791 MutexGuard aGuard( m_aMutex );
792 checkDisposed(Connection_BASE::rBHelper.bDisposed);
795 dispose();
798 // XWarningsSupplier
799 Any SAL_CALL Connection::getWarnings( )
801 // when you collected some warnings -> return it
802 return Any();
805 void SAL_CALL Connection::clearWarnings( )
807 // you should clear your collected warnings here
810 // XDocumentEventListener
811 void SAL_CALL Connection::documentEventOccured( const DocumentEvent& Event )
813 MutexGuard aGuard(m_aMutex);
815 if (!m_bIsEmbedded)
816 return;
818 if (Event.EventName != "OnSave" && Event.EventName != "OnSaveAs")
819 return;
821 commit(); // Commit and close transaction
822 if ( !(m_bIsEmbedded && m_xEmbeddedStorage.is()) )
823 return;
825 SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
828 runBackupService(isc_action_svc_backup);
830 catch (const SQLException& e)
832 auto a = cppu::getCaughtException();
833 throw WrappedTargetRuntimeException(e.Message, e.Context, a);
837 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation,
838 ElementModes::WRITE));
840 // TODO: verify the backup actually exists -- the backup service
841 // can fail without giving any sane error messages / telling us
842 // that it failed.
843 using namespace ::comphelper;
844 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
845 Reference< XInputStream > xInputStream;
846 if (!xContext.is())
847 return;
849 xInputStream =
850 OStorageHelper::GetInputStreamFromURL(m_sFBKPath, xContext);
851 if (xInputStream.is())
852 OStorageHelper::CopyInputToOutput( xInputStream,
853 xDBStream->getOutputStream());
855 // remove old fdb file if exists
856 uno::Reference< ucb::XSimpleFileAccess > xFileAccess =
857 ucb::SimpleFileAccess::create(xContext);
858 if (xFileAccess->exists(m_sFirebirdURL))
859 xFileAccess->kill(m_sFirebirdURL);
861 // XEventListener
862 void SAL_CALL Connection::disposing(const EventObject& /*rSource*/)
864 MutexGuard aGuard( m_aMutex );
866 m_xEmbeddedStorage.clear();
869 void Connection::buildTypeInfo()
871 MutexGuard aGuard( m_aMutex );
873 Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
874 Reference< XRow> xRow(xRs,UNO_QUERY);
875 // Information for a single SQL type
877 // Loop on the result set until we reach end of file
879 while (xRs->next ())
881 OTypeInfo aInfo;
882 aInfo.aTypeName = xRow->getString (1);
883 aInfo.nType = xRow->getShort (2);
884 aInfo.nPrecision = xRow->getInt (3);
885 // aLiteralPrefix = xRow->getString (4);
886 // aLiteralSuffix = xRow->getString (5);
887 // aCreateParams = xRow->getString (6);
888 // bNullable = xRow->getBoolean (7);
889 // bCaseSensitive = xRow->getBoolean (8);
890 // nSearchType = xRow->getShort (9);
891 // bUnsigned = xRow->getBoolean (10);
892 // bCurrency = xRow->getBoolean (11);
893 // bAutoIncrement = xRow->getBoolean (12);
894 aInfo.aLocalTypeName = xRow->getString (13);
895 // nMinimumScale = xRow->getShort (14);
896 aInfo.nMaximumScale = xRow->getShort (15);
897 // nNumPrecRadix = (sal_Int16)xRow->getInt(18);
900 // Now that we have the type info, save it
901 // in the Hashtable if we don't already have an
902 // entry for this SQL type.
904 m_aTypeInfo.push_back(aInfo);
907 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
908 "Type info built.");
910 // Close the result set/statement.
912 Reference< XCloseable> xClose(xRs,UNO_QUERY);
913 xClose->close();
915 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
916 "Closed.");
919 void Connection::disposing()
921 MutexGuard aGuard(m_aMutex);
923 disposeStatements();
925 m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>();
927 ISC_STATUS_ARRAY status; /* status vector */
928 if (m_aTransactionHandle)
930 // TODO: confirm whether we need to ask the user here.
931 isc_rollback_transaction(status, &m_aTransactionHandle);
934 if (m_aDBHandle)
936 if (isc_detach_database(status, &m_aDBHandle))
938 evaluateStatusVector(status, u"isc_detach_database", *this);
941 // TODO: write to storage again?
943 cppu::WeakComponentImplHelperBase::disposing();
945 m_pDatabaseFileDir.reset();
948 void Connection::disposeStatements()
950 MutexGuard aGuard(m_aMutex);
951 for (auto const& statement : m_aStatements)
953 Reference< XComponent > xComp(statement.get(), UNO_QUERY);
954 if (xComp.is())
955 xComp->dispose();
957 m_aStatements.clear();
960 uno::Reference< XTablesSupplier > Connection::createCatalog()
962 MutexGuard aGuard(m_aMutex);
964 // m_xCatalog is a weak reference. Reuse it if it still exists.
965 Reference< XTablesSupplier > xCatalog = m_xCatalog;
966 if (xCatalog.is())
968 return xCatalog;
970 else
972 xCatalog = new Catalog(this);
973 m_xCatalog = xCatalog;
974 return m_xCatalog;
979 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */