bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / firebird / Connection.cxx
blob5e61aa5a0f0aecda3abe2fb4b4b89c512f54074b
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 "Driver.hxx"
26 #include "PreparedStatement.hxx"
27 #include "Statement.hxx"
28 #include "Util.hxx"
30 #include <stdexcept>
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;
74 /**
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" );
79 /**
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)
86 , m_sConnectionURL()
87 , m_sFirebirdURL()
88 , m_bIsEmbedded(false)
89 , m_bIsFile(false)
90 , m_bIsAutoCommit(true)
91 , m_bIsReadOnly(false)
92 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
93 #if SAL_TYPES_SIZEOFPOINTER == 8
94 , m_aDBHandle(0)
95 , m_aTransactionHandle(0)
96 #else
97 , m_aDBHandle(nullptr)
98 , m_aTransactionHandle(nullptr)
99 #endif
100 , m_xCatalog(nullptr)
101 , m_xMetaData(nullptr)
102 , m_aStatements()
106 Connection::~Connection()
108 if(!isClosed())
109 close();
112 namespace {
114 struct ConnectionGuard
116 oslInterlockedCount& m_refCount;
117 explicit ConnectionGuard(oslInterlockedCount& refCount)
118 : m_refCount(refCount)
120 osl_atomic_increment(&m_refCount);
122 ~ConnectionGuard()
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);
177 if (!bIsNewDatabase)
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");
189 bIsFdbStored = true;
190 loadDatabaseFile(our_sFDBLocation, m_sFirebirdURL);
192 else
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://"))
208 m_bIsFile = true;
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");
245 else
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 */
268 ISC_STATUS aErr;
269 const OString sFirebirdURL = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
270 if (bIsNewDatabase)
272 aErr = isc_create_database(status,
273 sFirebirdURL.getLength(),
274 sFirebirdURL.getStr(),
275 &m_aDBHandle,
276 dpbBuffer.size(),
277 dpbBuffer.c_str(),
279 if (aErr)
281 evaluateStatusVector(status, u"isc_create_database", *this);
284 else
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(),
294 &m_aDBHandle,
295 dpbBuffer.size(),
296 dpbBuffer.c_str());
297 if (aErr)
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);
311 else
312 assert(false);
315 catch (const Exception&)
317 throw;
319 catch (const std::exception&)
321 throw;
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,
347 *pBlobId);
349 m_aStatements.push_back(WeakReferenceHelper(xReturn));
350 return 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,
360 *pBlobId);
362 m_aStatements.push_back(WeakReferenceHelper(xReturn));
363 return xReturn;
366 //----- XUnoTunnel ----------------------------------------------------------
367 // virtual
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);
373 // static
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);
386 // the pre
387 if(m_aTypeInfo.empty())
388 buildTypeInfo();
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));
394 return 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())
406 buildTypeInfo();
408 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql);
409 m_aStatements.push_back(WeakReferenceHelper(xReturn));
411 return xReturn;
414 Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
415 const OUString& _sSql )
417 SAL_INFO("connectivity.firebird", "prepareCall(). "
418 "_sSql: " << _sSql);
420 MutexGuard aGuard( m_aMutex );
421 checkDisposed(Connection_BASE::rBHelper.bDisposed);
423 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
425 // not implemented yet :-) a task to do
426 return nullptr;
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.
433 return _sSql;
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)
445 setupTransaction();
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
463 // is lost...
464 if (m_aTransactionHandle)
466 disposeStatements();
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;
476 break;
477 case TransactionIsolation::READ_COMMITTED:
478 aTransactionIsolation = isc_tpb_read_committed;
479 break;
480 case TransactionIsolation::REPEATABLE_READ:
481 aTransactionIsolation = isc_tpb_consistency;
482 break;
483 case TransactionIsolation::SERIALIZABLE:
484 aTransactionIsolation = isc_tpb_consistency;
485 break;
486 default:
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)
492 char aTPB[5];
493 char* pTPB = aTPB;
495 *pTPB++ = isc_tpb_version3;
496 if (m_bIsAutoCommit)
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,
505 &m_aDBHandle,
506 pTPB - aTPB, // bytes used in TPB
507 aTPB);
509 evaluateStatusVector(status_vector,
510 u"isc_start_transaction",
511 *this);
514 isc_tr_handle& Connection::getTransaction()
516 MutexGuard aGuard( m_aMutex );
517 if (!m_aTransactionHandle)
519 setupTransaction();
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)
533 disposeStatements();
534 isc_commit_transaction(status_vector, &m_aTransactionHandle);
535 evaluateStatusVector(status_vector,
536 u"isc_commit_transaction",
537 *this);
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;
563 #else
564 isc_svc_handle aServiceHandle = nullptr;
565 #endif
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());
574 *pSPB++ = aLength;
575 strncpy(pSPB,
576 OUStringToOString(sUserName,
577 RTL_TEXTENCODING_UTF8).getStr(),
578 aLength);
579 pSPB += aLength;
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
583 "service_mgr",
584 &aServiceHandle,
585 pSPB - aSPBBuffer,
586 aSPBBuffer))
588 evaluateStatusVector(aStatusVector,
589 u"isc_service_attach",
590 *this);
593 return aServiceHandle;
596 void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
598 ISC_STATUS_ARRAY aStatusVector;
599 if (isc_service_detach(aStatusVector,
600 &aServiceHandle))
602 evaluateStatusVector(aStatusVector,
603 u"isc_service_detach",
604 *this);
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
640 char sOptions[4];
641 char * pOptions = sOptions;
642 #ifdef _WIN32
643 #pragma warning(push)
644 #pragma warning(disable: 4310) // cast truncates data
645 #endif
646 ADD_SPB_NUMERIC(pOptions, isc_spb_res_create);
647 #ifdef _WIN32
648 #pragma warning(pop)
649 #endif
650 aRequest.append(sOptions, 4);
653 isc_svc_handle aServiceHandle;
654 aServiceHandle = attachServiceManager();
656 if (isc_service_start(aStatusVector,
657 &aServiceHandle,
658 nullptr,
659 aRequest.getLength(),
660 aRequest.getStr()))
662 evaluateStatusVector(aStatusVector, u"isc_service_start", *this);
665 char aInfoSPB = isc_info_svc_line;
666 char aResults[256];
668 // query blocks until success or error
669 if(isc_service_query(aStatusVector,
670 &aServiceHandle,
671 nullptr, // Reserved null
672 0,nullptr, // "send" spb -- size and spb -- not needed?
674 &aInfoSPB,
675 sizeof(aResults),
676 aResults))
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;
714 if(!xMetaData.is())
716 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
717 m_xMetaData = xMetaData;
720 return 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;
729 setupTransaction();
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);
748 return OUString();
751 void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level )
753 MutexGuard aGuard( m_aMutex );
754 checkDisposed(Connection_BASE::rBHelper.bDisposed);
756 m_aTransactionIsolation = level;
757 setupTransaction();
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 );
771 return nullptr;
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);
788 dispose();
791 // XWarningsSupplier
792 Any SAL_CALL Connection::getWarnings( )
794 // when you collected some warnings -> return it
795 return Any();
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);
808 if (!m_bIsEmbedded)
809 return;
811 if (Event.EventName != "OnSave" && Event.EventName != "OnSaveAs")
812 return;
814 commit(); // Commit and close transaction
815 if ( !(m_bIsEmbedded && m_xEmbeddedStorage.is()) )
816 return;
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
835 // that it failed.
836 using namespace ::comphelper;
837 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
838 Reference< XInputStream > xInputStream;
839 if (!xContext.is())
840 return;
842 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);
854 // XEventListener
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
872 while (xRs->next ())
874 OTypeInfo aInfo;
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(). "
901 "Type info built.");
903 // Close the result set/statement.
905 Reference< XCloseable> xClose(xRs,UNO_QUERY);
906 xClose->close();
908 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
909 "Closed.");
912 void Connection::disposing()
914 MutexGuard aGuard(m_aMutex);
916 disposeStatements();
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);
927 if (m_aDBHandle)
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);
951 if (xComp.is())
952 xComp->dispose();
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;
963 if (xCatalog.is())
965 return xCatalog;
967 else
969 xCatalog = new Catalog(this);
970 m_xCatalog = xCatalog;
971 return m_xCatalog;
976 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */