LCOV - code coverage report
Current view: top level - connectivity/source/drivers/firebird - Connection.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 209 381 54.9 %
Date: 2014-11-03 Functions: 23 45 51.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      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"
      28             : 
      29             : #include <stdexcept>
      30             : 
      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/sdbc/ColumnValue.hpp>
      44             : #include <com/sun/star/sdbc/XRow.hpp>
      45             : #include <com/sun/star/sdbc/TransactionIsolation.hpp>
      46             : #include <com/sun/star/ucb/SimpleFileAccess.hpp>
      47             : #include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
      48             : 
      49             : #include <connectivity/dbexception.hxx>
      50             : #include <connectivity/sqlparse.hxx>
      51             : #include <resource/common_res.hrc>
      52             : #include <resource/hsqldb_res.hrc>
      53             : #include <resource/sharedresources.hxx>
      54             : 
      55             : #include <comphelper/processfactory.hxx>
      56             : #include <comphelper/storagehelper.hxx>
      57             : #include <unotools/tempfile.hxx>
      58             : #include <unotools/localfilehelper.hxx>
      59             : #include <unotools/ucbstreamhelper.hxx>
      60             : 
      61             : using namespace connectivity::firebird;
      62             : using namespace connectivity;
      63             : 
      64             : using namespace ::osl;
      65             : 
      66             : using namespace ::com::sun::star;
      67             : using namespace ::com::sun::star::beans;
      68             : using namespace ::com::sun::star::container;
      69             : using namespace ::com::sun::star::document;
      70             : using namespace ::com::sun::star::embed;
      71             : using namespace ::com::sun::star::frame;
      72             : using namespace ::com::sun::star::io;
      73             : using namespace ::com::sun::star::lang;
      74             : using namespace ::com::sun::star::sdbc;
      75             : using namespace ::com::sun::star::sdbcx;
      76             : using namespace ::com::sun::star::uno;
      77             : 
      78           4 : const OUString Connection::our_sDBLocation( "firebird.fdb" );
      79             : 
      80           4 : Connection::Connection(FirebirdDriver*    _pDriver)
      81             :     : Connection_BASE(m_aMutex)
      82             :     , OSubComponent<Connection, Connection_BASE>((::cppu::OWeakObject*)_pDriver, this)
      83             :     , m_xDriver(_pDriver)
      84             :     , m_sConnectionURL()
      85             :     , m_sFirebirdURL()
      86             :     , m_bIsEmbedded(false)
      87             :     , m_xEmbeddedStorage(0)
      88             :     , m_bIsFile(false)
      89             :     , m_sUser()
      90             :     , m_bIsAutoCommit(false)
      91             :     , m_bIsReadOnly(false)
      92             :     , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
      93             :     , m_aDBHandle(0)
      94             :     , m_aTransactionHandle(0)
      95             :     , m_xCatalog(0)
      96             :     , m_xMetaData(0)
      97           4 :     , m_aStatements()
      98             : {
      99           4 : }
     100             : 
     101          12 : Connection::~Connection()
     102             : {
     103           4 :     if(!isClosed())
     104           0 :         close();
     105           8 : }
     106             : 
     107         235 : void SAL_CALL Connection::release() throw()
     108             : {
     109         235 :     relase_ChildImpl();
     110         235 : }
     111             : 
     112             : struct ConnectionGuard
     113             : {
     114             :     oslInterlockedCount& m_refCount;
     115           4 :     ConnectionGuard(oslInterlockedCount& refCount)
     116           4 :         : m_refCount(refCount)
     117             :     {
     118           4 :         osl_atomic_increment(&m_refCount);
     119           4 :     }
     120           4 :     ~ConnectionGuard()
     121             :     {
     122           4 :         osl_atomic_decrement(&m_refCount);
     123           4 :     }
     124             : };
     125             : 
     126           4 : void Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyValue >& info)
     127             :     throw (SQLException, RuntimeException, std::exception)
     128             : {
     129           4 :     ConnectionGuard aGuard(m_refCount);
     130             : 
     131             :     try
     132             :     {
     133           4 :         m_sConnectionURL = url;
     134             : 
     135           4 :         bool bIsNewDatabase = false;
     136           4 :         OUString aStorageURL;
     137           4 :         if (url.equals("sdbc:embedded:firebird"))
     138             :         {
     139           4 :             m_bIsEmbedded = true;
     140             : 
     141           4 :             const PropertyValue* pIter = info.getConstArray();
     142           4 :             const PropertyValue* pEnd = pIter + info.getLength();
     143             : 
     144          16 :             for (;pIter != pEnd; ++pIter)
     145             :             {
     146          12 :                 if ( pIter->Name == "Storage" )
     147             :                 {
     148           4 :                     m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY);
     149             :                 }
     150           8 :                 else if ( pIter->Name == "URL" )
     151             :                 {
     152           4 :                     pIter->Value >>= aStorageURL;
     153             :                 }
     154           4 :                 else if ( pIter->Name == "Document" )
     155             :                 {
     156           4 :                     pIter->Value >>= m_xParentDocument;
     157             :                 }
     158             :             }
     159             : 
     160           4 :             if ( !m_xEmbeddedStorage.is() )
     161             :             {
     162           0 :                 ::connectivity::SharedResources aResources;
     163           0 :                 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
     164           0 :                 ::dbtools::throwGenericSQLException(sMessage ,*this);
     165             :             }
     166             : 
     167           4 :             bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
     168             : 
     169           4 :             m_pExtractedFDBFile.reset(new ::utl::TempFile(NULL, true));
     170           4 :             m_sFirebirdURL = m_pExtractedFDBFile->GetFileName() + "/firebird.fdb";
     171             : 
     172             :             SAL_INFO("connectivity.firebird", "Temporary .fdb location:  " << m_sFirebirdURL);
     173             : 
     174           4 :             if (!bIsNewDatabase)
     175             :             {
     176             :                 SAL_INFO("connectivity.firebird", "Extracting .fdb from .odb" );
     177           2 :                 if (!m_xEmbeddedStorage->isStreamElement(our_sDBLocation))
     178             :                 {
     179           0 :                     ::connectivity::SharedResources aResources;
     180           0 :                     const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
     181           0 :                     ::dbtools::throwGenericSQLException(sMessage ,*this);
     182             :                 }
     183             : 
     184           2 :                 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sDBLocation,
     185           2 :                                                                 ElementModes::READ));
     186             : 
     187             :                 uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess(
     188             :                         ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ),
     189           4 :                                                                     uno::UNO_QUERY );
     190           2 :                 if ( !xFileAccess.is() )
     191             :                 {
     192           0 :                     ::connectivity::SharedResources aResources;
     193           0 :                     const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
     194           0 :                     ::dbtools::throwGenericSQLException(sMessage ,*this);
     195             :                 }
     196             : 
     197           4 :                 xFileAccess->writeFile(m_sFirebirdURL,xDBStream->getInputStream());
     198             :             }
     199             :             // TOOO: Get DB properties from XML
     200             : 
     201             :         }
     202             :         // External file AND/OR remote connection
     203           0 :         else if (url.startsWith("sdbc:firebird:"))
     204             :         {
     205           0 :             m_sFirebirdURL = url.copy(OUString("sdbc:firebird:").getLength());
     206           0 :             if (m_sFirebirdURL.startsWith("file://"))
     207             :             {
     208           0 :                 m_bIsFile = true;
     209             :                 uno::Reference< ucb::XSimpleFileAccess > xFileAccess(
     210             :                     ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()),
     211           0 :                     uno::UNO_QUERY);
     212           0 :                 if (!xFileAccess->exists(m_sFirebirdURL))
     213           0 :                     bIsNewDatabase = true;
     214             : 
     215           0 :                 m_sFirebirdURL = m_sFirebirdURL.copy(OUString("file://").getLength());
     216             :             }
     217             :         }
     218             : 
     219             :         char dpbBuffer[1 + 3 + 257 + 257 ]; // Expand as needed
     220           4 :         int dpbLength = 0;
     221             :         {
     222             :             char* dpb;
     223           4 :             char userName[256] = "";
     224           4 :             char userPassword[256] = "";
     225             : 
     226           4 :             dpb = dpbBuffer;
     227           4 :             *dpb++ = isc_dpb_version1;
     228             : 
     229           4 :             *dpb++ = isc_dpb_sql_dialect;
     230           4 :             *dpb++ = 1; // 1 byte long
     231           4 :             *dpb++ = FIREBIRD_SQL_DIALECT;
     232             :             // Do any more dpbBuffer additions here
     233             : 
     234           4 :             if (m_bIsEmbedded || m_bIsFile)
     235             :             {
     236           4 :                 *dpb++ = isc_dpb_trusted_auth;
     237           4 :                 *dpb++ = 1; // Length of data
     238           4 :                 *dpb++ = 1; // TRUE
     239             :             }
     240             :             else
     241             :             {
     242             :                 // TODO: parse password from connection string as needed?
     243             :             }
     244             : 
     245           4 :             if (strlen(userName))
     246             :             {
     247           0 :                 int nUsernameLength = strlen(userName);
     248           0 :                 *dpb++ = isc_dpb_user_name;
     249           0 :                 *dpb++ = (char) nUsernameLength;
     250           0 :                 strcpy(dpb, userName);
     251           0 :                 dpb+= nUsernameLength;
     252             :             }
     253             : 
     254           4 :             if (strlen(userPassword))
     255             :             {
     256           0 :                 int nPasswordLength = strlen(userPassword);
     257           0 :                 *dpb++ = isc_dpb_password;
     258           0 :                 *dpb++ = (char) nPasswordLength;
     259           0 :                 strcpy(dpb, userPassword);
     260           0 :                 dpb+= nPasswordLength;
     261             :             }
     262             : 
     263           4 :             dpbLength = dpb - dpbBuffer;
     264             :         }
     265             : 
     266             :         ISC_STATUS_ARRAY status;            /* status vector */
     267             :         ISC_STATUS aErr;
     268           4 :         if (bIsNewDatabase)
     269             :         {
     270             :             aErr = isc_create_database(status,
     271           2 :                                        m_sFirebirdURL.getLength(),
     272             :                                        OUStringToOString(m_sFirebirdURL,RTL_TEXTENCODING_UTF8).getStr(),
     273             :                                        &m_aDBHandle,
     274             :                                        dpbLength,
     275             :                                        dpbBuffer,
     276           4 :                                        0);
     277           2 :             if (aErr)
     278             :             {
     279           0 :                 evaluateStatusVector(status, "isc_create_database", *this);
     280             :             }
     281             :         }
     282             :         else
     283             :         {
     284             :             aErr = isc_attach_database(status,
     285           2 :                                        m_sFirebirdURL.getLength(),
     286             :                                        OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8).getStr(),
     287             :                                        &m_aDBHandle,
     288             :                                        dpbLength,
     289           4 :                                        dpbBuffer);
     290           2 :             if (aErr)
     291             :             {
     292           0 :                 evaluateStatusVector(status, "isc_attach_database", *this);
     293             :             }
     294             :         }
     295             : 
     296           4 :         if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed
     297             :         {
     298             :             // TODO: this is only needed when we change icu versions, so ideally
     299             :             // we somehow keep track of which icu version we have. There might
     300             :             // be something db internal that we can check, or we might have to store
     301             :             // it in the .odb.
     302           4 :             rebuildIndexes();
     303             : 
     304             :             // We need to attach as a document listener in order to be able to store
     305             :             // the temporary db back into the .odb when saving
     306           4 :             uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY);
     307             : 
     308           4 :             if (xBroadcaster.is())
     309           4 :                 xBroadcaster->addDocumentEventListener(this);
     310             :             else
     311           4 :                 assert(false);
     312           4 :         }
     313             :     }
     314           0 :     catch (const Exception&)
     315             :     {
     316           0 :         throw;
     317             :     }
     318           0 :     catch (const std::exception&)
     319             :     {
     320           0 :         throw;
     321             :     }
     322           0 :     catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
     323             : 
     324             :     {
     325           0 :         throw std::runtime_error("Generic Firebird::Exception");
     326           4 :     }
     327           4 : }
     328             : 
     329           0 : void Connection::notifyDatabaseModified()
     330             : {
     331           0 :     if (m_xParentDocument.is()) // Only true in embedded mode
     332           0 :         m_xParentDocument->setModified(sal_True);
     333           0 : }
     334             : 
     335             : //----- XServiceInfo ---------------------------------------------------------
     336           0 : IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection",
     337             :                                                     "com.sun.star.sdbc.Connection")
     338             : 
     339           0 : Reference< XBlob> Connection::createBlob(ISC_QUAD* pBlobId)
     340             :     throw(SQLException, RuntimeException)
     341             : {
     342           0 :     MutexGuard aGuard(m_aMutex);
     343           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     344             : 
     345             :     Reference< XBlob > xReturn = new Blob(&m_aDBHandle,
     346             :                                           &m_aTransactionHandle,
     347           0 :                                           *pBlobId);
     348             : 
     349           0 :     m_aStatements.push_back(WeakReferenceHelper(xReturn));
     350           0 :     return xReturn;
     351             : }
     352             : 
     353             : 
     354             : //----- XConnection ----------------------------------------------------------
     355          22 : Reference< XStatement > SAL_CALL Connection::createStatement( )
     356             :                                         throw(SQLException, RuntimeException, std::exception)
     357             : {
     358          22 :     MutexGuard aGuard( m_aMutex );
     359          22 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     360             : 
     361             :     // the pre
     362          22 :     if(m_aTypeInfo.empty())
     363           4 :         buildTypeInfo();
     364             : 
     365             :     // create a statement
     366             :     // the statement can only be executed once
     367          22 :     Reference< XStatement > xReturn = new OStatement(this);
     368          22 :     m_aStatements.push_back(WeakReferenceHelper(xReturn));
     369          22 :     return xReturn;
     370             : }
     371             : 
     372           0 : OUString Connection::transformPreparedStatement(const OUString& _sSQL)
     373             : {
     374           0 :     OUString sSqlStatement (_sSQL);
     375             :     try
     376             :     {
     377           0 :         OSQLParser aParser( m_xDriver->getContext() );
     378           0 :         OUString sErrorMessage;
     379           0 :         OUString sNewSql;
     380           0 :         OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
     381           0 :         if(pNode)
     382             :         {   // special handling for parameters
     383           0 :             OSQLParseNode::substituteParameterNames(pNode);
     384           0 :             pNode->parseNodeToStr( sNewSql, this );
     385           0 :             delete pNode;
     386           0 :             sSqlStatement = sNewSql;
     387           0 :         }
     388             :     }
     389           0 :     catch(const Exception&)
     390             :     {
     391             :         SAL_WARN("connectivity.firebird", "failed to remove named parameters from '" << _sSQL << "'");
     392             :     }
     393           0 :     return sSqlStatement;
     394             : }
     395             : 
     396           0 : Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
     397             :             const OUString& _sSql)
     398             :     throw(SQLException, RuntimeException, std::exception)
     399             : {
     400             :     SAL_INFO("connectivity.firebird", "prepareStatement() "
     401             :              "called with sql: " << _sSql);
     402           0 :     MutexGuard aGuard(m_aMutex);
     403           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     404             : 
     405           0 :     if(m_aTypeInfo.empty())
     406           0 :         buildTypeInfo();
     407             : 
     408           0 :     OUString sSqlStatement (transformPreparedStatement( _sSql ));
     409             : 
     410             :     Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,
     411             :                                                                      m_aTypeInfo,
     412           0 :                                                                      sSqlStatement);
     413           0 :     m_aStatements.push_back(WeakReferenceHelper(xReturn));
     414             : 
     415           0 :     return xReturn;
     416             : }
     417             : 
     418           0 : Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
     419             :                 const OUString& _sSql ) throw(SQLException, RuntimeException, std::exception)
     420             : {
     421             :     SAL_INFO("connectivity.firebird", "prepareCall(). "
     422             :              "_sSql: " << _sSql);
     423             : 
     424           0 :     MutexGuard aGuard( m_aMutex );
     425           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     426             : 
     427             :     // OUString sSqlStatement (transformPreparedStatement( _sSql ));
     428             : 
     429             :     // not implemented yet :-) a task to do
     430           0 :     return NULL;
     431             : }
     432             : 
     433           0 : OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql )
     434             :                                         throw(SQLException, RuntimeException, std::exception)
     435             : {
     436           0 :     MutexGuard aGuard( m_aMutex );
     437             :     // We do not need to adapt the SQL for Firebird atm.
     438           0 :     return _sSql;
     439             : }
     440             : 
     441           0 : void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit )
     442             :                                         throw(SQLException, RuntimeException, std::exception)
     443             : {
     444           0 :     MutexGuard aGuard( m_aMutex );
     445           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     446             : 
     447           0 :     m_bIsAutoCommit = autoCommit;
     448             : 
     449           0 :     if (m_aTransactionHandle)
     450             :     {
     451           0 :         setupTransaction();
     452           0 :     }
     453           0 : }
     454             : 
     455           0 : sal_Bool SAL_CALL Connection::getAutoCommit() throw(SQLException, RuntimeException, std::exception)
     456             : {
     457           0 :     MutexGuard aGuard( m_aMutex );
     458           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     459             : 
     460           0 :     return m_bIsAutoCommit;
     461             : }
     462             : 
     463           8 : void Connection::setupTransaction()
     464             :     throw (SQLException)
     465             : {
     466           8 :     MutexGuard aGuard( m_aMutex );
     467             :     ISC_STATUS status_vector[20];
     468             : 
     469             :     // TODO: is this sensible? If we have changed parameters then transaction
     470             :     // is lost...
     471           8 :     if (m_aTransactionHandle)
     472             :     {
     473           0 :         disposeStatements();
     474           0 :         isc_rollback_transaction(status_vector, &m_aTransactionHandle);
     475             :     }
     476             : 
     477           8 :     char aTransactionIsolation = 0;
     478           8 :     switch (m_aTransactionIsolation)
     479             :     {
     480             :         // TODO: confirm that these are correct.
     481             :         case(TransactionIsolation::READ_UNCOMMITTED):
     482           0 :             aTransactionIsolation = isc_tpb_concurrency;
     483           0 :             break;
     484             :         case(TransactionIsolation::READ_COMMITTED):
     485           0 :             aTransactionIsolation = isc_tpb_read_committed;
     486           0 :             break;
     487             :         case(TransactionIsolation::REPEATABLE_READ):
     488           8 :             aTransactionIsolation = isc_tpb_consistency;
     489           8 :             break;
     490             :         case(TransactionIsolation::SERIALIZABLE):
     491           0 :             aTransactionIsolation = isc_tpb_consistency;
     492           0 :             break;
     493             :         default:
     494             :             assert( false ); // We must have a valid TransactionIsolation.
     495             :     }
     496             : 
     497             :     // You cannot pass an empty tpb parameter so we have to do some pointer
     498             :     // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
     499             :     char aTPB[5];
     500           8 :     char* pTPB = aTPB;
     501             : 
     502           8 :     *pTPB++ = isc_tpb_version3;
     503           8 :     if (m_bIsAutoCommit)
     504           0 :         *pTPB++ = isc_tpb_autocommit;
     505           8 :     *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read);
     506           8 :     *pTPB++ = aTransactionIsolation;
     507           8 :     *pTPB++ = isc_tpb_wait;
     508             : 
     509             :     isc_start_transaction(status_vector,
     510             :                           &m_aTransactionHandle,
     511             :                           1,
     512             :                           &m_aDBHandle,
     513             :                           pTPB - aTPB, // bytes used in TPB
     514           8 :                           aTPB);
     515             : 
     516             :     evaluateStatusVector(status_vector,
     517             :                          "isc_start_transaction",
     518           8 :                          *this);
     519           8 : }
     520             : 
     521          36 : isc_tr_handle& Connection::getTransaction()
     522             :     throw (SQLException)
     523             : {
     524          36 :     MutexGuard aGuard( m_aMutex );
     525          36 :     if (!m_aTransactionHandle)
     526             :     {
     527           8 :         setupTransaction();
     528             :     }
     529          36 :     return m_aTransactionHandle;
     530             : }
     531             : 
     532           4 : void SAL_CALL Connection::commit() throw(SQLException, RuntimeException, std::exception)
     533             : {
     534           4 :     MutexGuard aGuard( m_aMutex );
     535           4 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     536             : 
     537             :     ISC_STATUS status_vector[20];
     538             : 
     539           4 :     if (!m_bIsAutoCommit && m_aTransactionHandle)
     540             :     {
     541           4 :         disposeStatements();
     542           4 :         isc_commit_transaction(status_vector, &m_aTransactionHandle);
     543             :         evaluateStatusVector(status_vector,
     544             :                              "isc_commit_transaction",
     545           4 :                              *this);
     546           4 :     }
     547           4 : }
     548             : 
     549           0 : void SAL_CALL Connection::rollback() throw(SQLException, RuntimeException, std::exception)
     550             : {
     551           0 :     MutexGuard aGuard( m_aMutex );
     552           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     553             : 
     554             :     ISC_STATUS status_vector[20];
     555             : 
     556           0 :     if (!m_bIsAutoCommit && m_aTransactionHandle)
     557             :     {
     558           0 :         isc_rollback_transaction(status_vector, &m_aTransactionHandle);
     559           0 :     }
     560           0 : }
     561             : 
     562           4 : sal_Bool SAL_CALL Connection::isClosed(  ) throw(SQLException, RuntimeException, std::exception)
     563             : {
     564           4 :     MutexGuard aGuard( m_aMutex );
     565             : 
     566             :     // just simple -> we are close when we are disposed taht means someone called dispose(); (XComponent)
     567           4 :     return Connection_BASE::rBHelper.bDisposed;
     568             : }
     569             : 
     570          56 : Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData(  ) throw(SQLException, RuntimeException, std::exception)
     571             : {
     572          56 :     MutexGuard aGuard( m_aMutex );
     573          56 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     574             : 
     575             :     // here we have to create the class with biggest interface
     576             :     // The answer is 42 :-)
     577          56 :     Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
     578          56 :     if(!xMetaData.is())
     579             :     {
     580           8 :         xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
     581           8 :         m_xMetaData = xMetaData;
     582             :     }
     583             : 
     584          56 :     return xMetaData;
     585             : }
     586             : 
     587           0 : void SAL_CALL Connection::setReadOnly(sal_Bool readOnly)
     588             :                                             throw(SQLException, RuntimeException, std::exception)
     589             : {
     590           0 :     MutexGuard aGuard( m_aMutex );
     591           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     592             : 
     593           0 :     m_bIsReadOnly = readOnly;
     594           0 :     setupTransaction();
     595           0 : }
     596             : 
     597           0 : sal_Bool SAL_CALL Connection::isReadOnly() throw(SQLException, RuntimeException, std::exception)
     598             : {
     599           0 :     MutexGuard aGuard( m_aMutex );
     600           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     601             : 
     602           0 :     return m_bIsReadOnly;
     603             : }
     604             : 
     605           0 : void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/)
     606             :     throw(SQLException, RuntimeException, std::exception)
     607             : {
     608           0 :     ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this);
     609           0 : }
     610             : 
     611           0 : OUString SAL_CALL Connection::getCatalog()
     612             :     throw(SQLException, RuntimeException, std::exception)
     613             : {
     614           0 :     ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this);
     615           0 :     return OUString();
     616             : }
     617             : 
     618           0 : void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException, std::exception)
     619             : {
     620           0 :     MutexGuard aGuard( m_aMutex );
     621           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     622             : 
     623           0 :     m_aTransactionIsolation = level;
     624           0 :     setupTransaction();
     625           0 : }
     626             : 
     627           0 : sal_Int32 SAL_CALL Connection::getTransactionIsolation(  ) throw(SQLException, RuntimeException, std::exception)
     628             : {
     629           0 :     MutexGuard aGuard( m_aMutex );
     630           0 :     checkDisposed(Connection_BASE::rBHelper.bDisposed);
     631             : 
     632           0 :     return m_aTransactionIsolation;
     633             : }
     634             : 
     635           0 : Reference< XNameAccess > SAL_CALL Connection::getTypeMap() throw(SQLException, RuntimeException, std::exception)
     636             : {
     637           0 :     ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
     638           0 :     return 0;
     639             : }
     640             : 
     641           0 : void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >& typeMap)
     642             :                                             throw(SQLException, RuntimeException, std::exception)
     643             : {
     644           0 :     ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
     645             :     (void) typeMap;
     646           0 : }
     647             : 
     648             : //----- XCloseable -----------------------------------------------------------
     649           4 : void SAL_CALL Connection::close(  ) throw(SQLException, RuntimeException, std::exception)
     650             : {
     651             :     // we just dispose us
     652             :     {
     653           4 :         MutexGuard aGuard( m_aMutex );
     654           4 :         checkDisposed(Connection_BASE::rBHelper.bDisposed);
     655             : 
     656             :     }
     657           4 :     dispose();
     658           0 : }
     659             : 
     660             : // XWarningsSupplier
     661           0 : Any SAL_CALL Connection::getWarnings(  ) throw(SQLException, RuntimeException, std::exception)
     662             : {
     663             :     // when you collected some warnings -> return it
     664           0 :     return Any();
     665             : }
     666             : 
     667           0 : void SAL_CALL Connection::clearWarnings(  ) throw(SQLException, RuntimeException, std::exception)
     668             : {
     669             :     // you should clear your collected warnings here
     670           0 : }
     671             : 
     672             : // XDocumentEventListener
     673          13 : void SAL_CALL Connection::documentEventOccured( const DocumentEvent& _Event )
     674             :                                                         throw(RuntimeException, std::exception)
     675             : {
     676          13 :     MutexGuard aGuard(m_aMutex);
     677             : 
     678          13 :     if (!m_bIsEmbedded)
     679          13 :         return;
     680             : 
     681          13 :     if (_Event.EventName == "OnSave" || _Event.EventName == "OnSaveAs")
     682             :     {
     683           0 :         commit(); // Commit and close transaction
     684           0 :         if ( m_bIsEmbedded && m_xEmbeddedStorage.is() )
     685             :         {
     686             :             SAL_INFO("connectivity.firebird", "Writing .fdb into .odb" );
     687             : 
     688           0 :             Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sDBLocation,
     689           0 :                                                             ElementModes::WRITE));
     690             : 
     691             :             using namespace ::comphelper;
     692           0 :             Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
     693           0 :             Reference< XInputStream > xInputStream;
     694           0 :             if (xContext.is())
     695           0 :                 xInputStream =
     696           0 :                         OStorageHelper::GetInputStreamFromURL(m_sFirebirdURL, xContext);
     697           0 :             if (xInputStream.is())
     698             :                 OStorageHelper::CopyInputToOutput( xInputStream,
     699           0 :                                                 xDBStream->getOutputStream());
     700             :             // TODO: ensure db is in safe state
     701             :         }
     702          13 :     }
     703             : }
     704             : // XEventListener
     705           4 : void SAL_CALL Connection::disposing(const EventObject& /*rSource*/)
     706             :     throw (RuntimeException, std::exception)
     707             : {
     708           4 :     MutexGuard aGuard( m_aMutex );
     709             : 
     710           4 :     m_xEmbeddedStorage.clear();
     711           4 : }
     712             : 
     713           4 : void Connection::buildTypeInfo() throw( SQLException)
     714             : {
     715           4 :     MutexGuard aGuard( m_aMutex );
     716             : 
     717           8 :     Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
     718           8 :     Reference< XRow> xRow(xRs,UNO_QUERY);
     719             :     // Information for a single SQL type
     720             : 
     721             :     // Loop on the result set until we reach end of file
     722             : 
     723          52 :     while (xRs->next ())
     724             :     {
     725          44 :         OTypeInfo aInfo;
     726          44 :         aInfo.aTypeName         = xRow->getString   (1);
     727          44 :         aInfo.nType             = xRow->getShort    (2);
     728          44 :         aInfo.nPrecision        = xRow->getInt      (3);
     729          44 :         aInfo.aLiteralPrefix    = xRow->getString   (4);
     730          44 :         aInfo.aLiteralSuffix    = xRow->getString   (5);
     731          44 :         aInfo.aCreateParams     = xRow->getString   (6);
     732          44 :         aInfo.bNullable         = xRow->getBoolean  (7) == ColumnValue::NULLABLE;
     733          44 :         aInfo.bCaseSensitive    = xRow->getBoolean  (8);
     734          44 :         aInfo.nSearchType       = xRow->getShort    (9);
     735          44 :         aInfo.bUnsigned         = xRow->getBoolean  (10);
     736          44 :         aInfo.bCurrency         = xRow->getBoolean  (11);
     737          44 :         aInfo.bAutoIncrement    = xRow->getBoolean  (12);
     738          44 :         aInfo.aLocalTypeName    = xRow->getString   (13);
     739          44 :         aInfo.nMinimumScale     = xRow->getShort    (14);
     740          44 :         aInfo.nMaximumScale     = xRow->getShort    (15);
     741          44 :         aInfo.nNumPrecRadix     = (sal_Int16)xRow->getInt(18);
     742             : 
     743             : 
     744             : 
     745             :         // Now that we have the type info, save it
     746             :         // in the Hashtable if we don't already have an
     747             :         // entry for this SQL type.
     748             : 
     749          44 :         m_aTypeInfo.push_back(aInfo);
     750          44 :     }
     751             : 
     752             :     SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
     753             :              "Type info built.");
     754             : 
     755             :     // Close the result set/statement.
     756             : 
     757           8 :     Reference< XCloseable> xClose(xRs,UNO_QUERY);
     758           4 :     xClose->close();
     759             : 
     760             :     SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
     761           4 :              "Closed.");
     762           4 : }
     763             : 
     764           4 : void Connection::disposing()
     765             : {
     766           4 :     MutexGuard aGuard(m_aMutex);
     767             : 
     768           4 :     disposeStatements();
     769             : 
     770           4 :     m_xMetaData = ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbc::XDatabaseMetaData>();
     771             : 
     772             :     ISC_STATUS_ARRAY status;            /* status vector */
     773           4 :     if (m_aTransactionHandle)
     774             :     {
     775             :         // TODO: confirm whether we need to ask the user here.
     776           4 :         isc_rollback_transaction(status, &m_aTransactionHandle);
     777             :     }
     778             : 
     779           4 :     if (isc_detach_database(status, &m_aDBHandle))
     780             :     {
     781           0 :         evaluateStatusVector(status, "isc_detach_database", *this);
     782             :     }
     783             :     // TODO: write to storage again?
     784             : 
     785           4 :     dispose_ChildImpl();
     786           4 :     cppu::WeakComponentImplHelperBase::disposing();
     787           4 :     m_xDriver.clear();
     788             : 
     789           4 :     if (m_pExtractedFDBFile)
     790             :     {
     791           4 :         ::utl::removeTree(m_pExtractedFDBFile->GetURL());
     792           0 :         m_pExtractedFDBFile.reset();
     793           4 :     }
     794           0 : }
     795             : 
     796           8 : void Connection::disposeStatements()
     797             : {
     798           8 :     MutexGuard aGuard(m_aMutex);
     799          30 :     for (OWeakRefArray::iterator i = m_aStatements.begin(); m_aStatements.end() != i; ++i)
     800             :     {
     801          22 :         Reference< XComponent > xComp(i->get(), UNO_QUERY);
     802          22 :         if (xComp.is())
     803           8 :             xComp->dispose();
     804          22 :     }
     805           8 :     m_aStatements.clear();
     806           8 : }
     807             : 
     808           4 : uno::Reference< XTablesSupplier > Connection::createCatalog()
     809             : {
     810           4 :     MutexGuard aGuard(m_aMutex);
     811             : 
     812             :     // m_xCatalog is a weak reference. Reuse it if it still exists.
     813           8 :     Reference< XTablesSupplier > xCatalog = m_xCatalog;
     814           4 :     if (xCatalog.is())
     815             :     {
     816           0 :         return xCatalog;
     817             :     }
     818             :     else
     819             :     {
     820           4 :         xCatalog = new Catalog(this);
     821           4 :         m_xCatalog = xCatalog;
     822           4 :         return m_xCatalog;
     823           4 :     }
     824             : 
     825             : }
     826             : 
     827           4 : void Connection::rebuildIndexes() throw (SQLException, RuntimeException, std::exception)
     828             : {
     829           4 :     MutexGuard aGuard(m_aMutex);
     830             : 
     831             :     try
     832             :     {
     833             :         // We only need to do this for character based columns on user-created tables.
     834             : 
     835             :         // Ideally we'd use a FOR SELECT ... INTO .... DO ..., but that seems to
     836             :         // only be possible using PSQL, i.e. using a stored procedure.
     837             :         OUString sSql(
     838             :             // multiple columns possible per index, only select once
     839             :             "SELECT DISTINCT indices.RDB$INDEX_NAME "
     840             :             "FROM RDB$INDICES indices "
     841             :             "JOIN RDB$INDEX_SEGMENTS index_segments "
     842             :             "ON (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) "
     843             :             "JOIN RDB$RELATION_FIELDS relation_fields "
     844             :             "ON (index_segments.RDB$FIELD_NAME = relation_fields.RDB$FIELD_NAME) "
     845             :             "JOIN RDB$FIELDS fields "
     846             :             "ON (relation_fields.RDB$FIELD_SOURCE = fields.RDB$FIELD_NAME) "
     847             : 
     848             :             "WHERE (indices.RDB$SYSTEM_FLAG = 0) "
     849             :             // TODO: what about blr_text2 etc. ?
     850           8 :             "AND ((fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_text) + ") "
     851          16 :             "     OR (fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_varying) + ")) "
     852             :             "AND (indices.RDB$INDEX_INACTIVE IS NULL OR indices.RDB$INDEX_INACTIVE = 0) "
     853           8 :         );
     854             : 
     855           8 :         uno::Reference< XStatement > xCharIndicesStatement = createStatement();
     856             :         uno::Reference< XResultSet > xCharIndices =
     857           8 :                                         xCharIndicesStatement->executeQuery(sSql);
     858           8 :         uno::Reference< XRow > xRow(xCharIndices, UNO_QUERY_THROW);
     859             : 
     860           8 :         uno::Reference< XStatement > xAlterIndexStatement = createStatement();
     861             : 
     862             :         // ALTER is a DDL statement, hence using Statement will cause a commit
     863             :         // after every alter -- in this case this is inappropriate (xCharIndicesStatement
     864             :         // and its ResultSet become invalidated) hence we use the native api.
     865           8 :         while (xCharIndices->next())
     866             :         {
     867           0 :             OUString sIndexName(sanitizeIdentifier(xRow->getString(1)));
     868             :             SAL_INFO("connectivity.firebird", "rebuilding index " + sIndexName);
     869             :             OString sAlterIndex = "ALTER INDEX \""
     870           0 :                                    + OUStringToOString(sIndexName, RTL_TEXTENCODING_UTF8)
     871           0 :                                    + "\" ACTIVE";
     872             : 
     873             :             ISC_STATUS_ARRAY aStatusVector;
     874             :             ISC_STATUS aErr;
     875             : 
     876             :             aErr = isc_dsql_execute_immediate(aStatusVector,
     877           0 :                                               &getDBHandle(),
     878           0 :                                               &getTransaction(),
     879             :                                               0, // Length: 0 for null terminated
     880             :                                               sAlterIndex.getStr(),
     881             :                                               FIREBIRD_SQL_DIALECT,
     882           0 :                                               NULL);
     883           0 :             if (aErr)
     884             :                 evaluateStatusVector(aStatusVector,
     885             :                                      "rebuildIndexes:isc_dsql_execute_immediate",
     886           0 :                                      *this);
     887           0 :         }
     888           8 :         commit();
     889             :     }
     890           0 :     catch (const Exception&)
     891             :     {
     892           0 :         throw;
     893             :     }
     894           0 :     catch (const std::exception&)
     895             :     {
     896           0 :         throw;
     897             :     }
     898           0 :     catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
     899             :     {
     900           0 :         throw std::runtime_error("Generic Firebird::Exception");
     901           4 :     }
     902             : 
     903          16 : }
     904             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10