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

Generated by: LCOV version 1.10