1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "Catalog.hxx"
21 #include "Connection.hxx"
22 #include "DatabaseMetaData.hxx"
24 #include "PreparedStatement.hxx"
25 #include "Statement.hxx"
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>
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>
53 #include <comphelper/processfactory.hxx>
54 #include <comphelper/storagehelper.hxx>
55 #include <unotools/tempfile.hxx>
56 #include <unotools/ucbstreamhelper.hxx>
58 using namespace connectivity::firebird
;
59 using namespace connectivity
;
61 using namespace ::osl
;
63 using namespace ::com::sun::star
;
64 using namespace ::com::sun::star::beans
;
65 using namespace ::com::sun::star::container
;
66 using namespace ::com::sun::star::document
;
67 using namespace ::com::sun::star::embed
;
68 using namespace ::com::sun::star::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
;
75 const OUString
Connection::our_sDBLocation( "firebird.fdb" );
77 Connection::Connection(FirebirdDriver
* _pDriver
)
78 : Connection_BASE(m_aMutex
)
79 , OSubComponent
<Connection
, Connection_BASE
>((::cppu::OWeakObject
*)_pDriver
, this)
83 , m_bIsEmbedded(false)
84 , m_xEmbeddedStorage(0)
87 , m_bIsAutoCommit(false)
88 , m_bIsReadOnly(false)
89 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ
)
91 , m_aTransactionHandle(0)
99 Connection::~Connection()
104 m_pDriver
->release();
108 void SAL_CALL
Connection::release() throw()
113 void Connection::construct(const ::rtl::OUString
& url
, const Sequence
< PropertyValue
>& info
)
114 throw(SQLException
, RuntimeException
)
116 osl_atomic_increment( &m_refCount
);
118 m_sConnectionURL
= url
;
120 bool bIsNewDatabase
= false;
121 OUString aStorageURL
;
122 if (url
.equals("sdbc:embedded:firebird"))
124 m_bIsEmbedded
= true;
126 const PropertyValue
* pIter
= info
.getConstArray();
127 const PropertyValue
* pEnd
= pIter
+ info
.getLength();
129 for (;pIter
!= pEnd
; ++pIter
)
131 if ( pIter
->Name
== "Storage" )
133 m_xEmbeddedStorage
.set(pIter
->Value
,UNO_QUERY
);
135 else if ( pIter
->Name
== "URL" )
137 pIter
->Value
>>= aStorageURL
;
139 else if ( pIter
->Name
== "Document" )
141 pIter
->Value
>>= m_xParentDocument
;
145 if ( !m_xEmbeddedStorage
.is() )
147 ::connectivity::SharedResources aResources
;
148 const OUString sMessage
= aResources
.getResourceString(STR_NO_STORAGE
);
149 ::dbtools::throwGenericSQLException(sMessage
,*this);
152 bIsNewDatabase
= !m_xEmbeddedStorage
->hasElements();
154 m_pExtractedFDBFile
.reset(new ::utl::TempFile(NULL
, true));
155 m_pExtractedFDBFile
->EnableKillingFile();
156 m_sFirebirdURL
= m_pExtractedFDBFile
->GetFileName() + "/firebird.fdb";
158 SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL
);
162 SAL_INFO("connectivity.firebird", "Extracting .fdb from .odb" );
163 if (!m_xEmbeddedStorage
->isStreamElement(our_sDBLocation
))
165 ::connectivity::SharedResources aResources
;
166 const OUString sMessage
= aResources
.getResourceString(STR_ERROR_NEW_VERSION
);
167 ::dbtools::throwGenericSQLException(sMessage
,*this);
170 Reference
< XStream
> xDBStream(m_xEmbeddedStorage
->openStreamElement(our_sDBLocation
,
171 ElementModes::READ
));
173 uno::Reference
< ucb::XSimpleFileAccess2
> xFileAccess(
174 ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ),
176 if ( !xFileAccess
.is() )
178 ::connectivity::SharedResources aResources
;
179 const OUString sMessage
= aResources
.getResourceString(STR_ERROR_NEW_VERSION
);
180 ::dbtools::throwGenericSQLException(sMessage
,*this);
183 xFileAccess
->writeFile(m_sFirebirdURL
,xDBStream
->getInputStream());
185 // TOOO: Get DB properties from XML
188 // External file AND/OR remote connection
189 else if (url
.startsWith("sdbc:firebird:"))
191 m_sFirebirdURL
= url
.copy(OUString("sdbc:firebird:").getLength());
192 if (m_sFirebirdURL
.startsWith("file://"))
195 uno::Reference
< ucb::XSimpleFileAccess
> xFileAccess(
196 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()),
198 if (!xFileAccess
->exists(m_sFirebirdURL
))
199 bIsNewDatabase
= true;
201 m_sFirebirdURL
= m_sFirebirdURL
.copy(OUString("file://").getLength());
205 char dpbBuffer
[1 + 3 + 257 + 257 ]; // Expand as needed
209 char userName
[256] = "";
210 char userPassword
[256] = "";
213 *dpb
++ = isc_dpb_version1
;
215 *dpb
++ = isc_dpb_sql_dialect
;
216 *dpb
++ = 1; // 1 byte long
217 *dpb
++ = FIREBIRD_SQL_DIALECT
;
218 // Do any more dpbBuffer additions here
220 if (m_bIsEmbedded
|| m_bIsFile
)
222 *dpb
++ = isc_dpb_trusted_auth
;
223 *dpb
++ = 1; // Length of data
228 // TODO: parse password from connection string as needed?
231 if (strlen(userName
))
233 int nUsernameLength
= strlen(userName
);
234 *dpb
++ = isc_dpb_user_name
;
235 *dpb
++ = (char) nUsernameLength
;
236 strcpy(dpb
, userName
);
237 dpb
+= nUsernameLength
;
240 if (strlen(userPassword
))
242 int nPasswordLength
= strlen(userPassword
);
243 *dpb
++ = isc_dpb_password
;
244 *dpb
++ = (char) nPasswordLength
;
245 strcpy(dpb
, userPassword
);
246 dpb
+= nPasswordLength
;
249 dpbLength
= dpb
- dpbBuffer
;
252 ISC_STATUS_ARRAY status
; /* status vector */
256 aErr
= isc_create_database(status
,
257 m_sFirebirdURL
.getLength(),
258 OUStringToOString(m_sFirebirdURL
,RTL_TEXTENCODING_UTF8
).getStr(),
265 evaluateStatusVector(status
, "isc_create_database", *this);
270 aErr
= isc_attach_database(status
,
271 m_sFirebirdURL
.getLength(),
272 OUStringToOString(m_sFirebirdURL
, RTL_TEXTENCODING_UTF8
).getStr(),
278 evaluateStatusVector(status
, "isc_attach_database", *this);
282 if (m_bIsEmbedded
) // Add DocumentEventListener to save the .fdb as needed
284 // TODO: this is only needed when we change icu versions, so ideally
285 // we somehow keep track of which icu version we have. There might
286 // be something db internal that we can check, or we might have to store
290 // We need to attach as a document listener in order to be able to store
291 // the temporary db back into the .odb when saving
292 uno::Reference
<XDocumentEventBroadcaster
> xBroadcaster(m_xParentDocument
, UNO_QUERY
);
294 if (xBroadcaster
.is())
295 xBroadcaster
->addDocumentEventListener(this);
300 osl_atomic_decrement( &m_refCount
);
303 void Connection::notifyDatabaseModified()
305 if (m_xParentDocument
.is()) // Only true in embedded mode
306 m_xParentDocument
->setModified(sal_True
);
309 //----- XServiceInfo ---------------------------------------------------------
310 IMPLEMENT_SERVICE_INFO(Connection
, "com.sun.star.sdbc.drivers.firebird.Connection",
311 "com.sun.star.sdbc.Connection")
313 Reference
< XBlob
> Connection::createBlob(ISC_QUAD
* pBlobId
)
314 throw(SQLException
, RuntimeException
)
316 MutexGuard
aGuard(m_aMutex
);
317 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
319 Reference
< XBlob
> xReturn
= new Blob(&m_aDBHandle
,
320 &m_aTransactionHandle
,
323 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
328 //----- XConnection ----------------------------------------------------------
329 Reference
< XStatement
> SAL_CALL
Connection::createStatement( )
330 throw(SQLException
, RuntimeException
, std::exception
)
332 MutexGuard
aGuard( m_aMutex
);
333 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
336 if(m_aTypeInfo
.empty())
339 // create a statement
340 // the statement can only be executed once
341 Reference
< XStatement
> xReturn
= new OStatement(this);
342 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
346 OUString
Connection::transformPreparedStatement(const OUString
& _sSQL
)
348 OUString
sSqlStatement (_sSQL
);
351 OSQLParser
aParser( m_pDriver
->getContext() );
352 OUString sErrorMessage
;
354 OSQLParseNode
* pNode
= aParser
.parseTree(sErrorMessage
,_sSQL
);
356 { // special handling for parameters
357 OSQLParseNode::substituteParameterNames(pNode
);
358 pNode
->parseNodeToStr( sNewSql
, this );
360 sSqlStatement
= sNewSql
;
363 catch(const Exception
&)
365 SAL_WARN("connectivity.firebird", "failed to remove named parameters from '" << _sSQL
<< "'");
367 return sSqlStatement
;
370 Reference
< XPreparedStatement
> SAL_CALL
Connection::prepareStatement(
371 const OUString
& _sSql
)
372 throw(SQLException
, RuntimeException
, std::exception
)
374 SAL_INFO("connectivity.firebird", "prepareStatement() "
375 "called with sql: " << _sSql
);
376 MutexGuard
aGuard(m_aMutex
);
377 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
379 if(m_aTypeInfo
.empty())
382 OUString
sSqlStatement (transformPreparedStatement( _sSql
));
384 Reference
< XPreparedStatement
> xReturn
= new OPreparedStatement(this,
387 m_aStatements
.push_back(WeakReferenceHelper(xReturn
));
392 Reference
< XPreparedStatement
> SAL_CALL
Connection::prepareCall(
393 const OUString
& _sSql
) throw(SQLException
, RuntimeException
, std::exception
)
395 SAL_INFO("connectivity.firebird", "prepareCall(). "
398 MutexGuard
aGuard( m_aMutex
);
399 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
401 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
403 // not implemented yet :-) a task to do
407 OUString SAL_CALL
Connection::nativeSQL( const OUString
& _sSql
)
408 throw(SQLException
, RuntimeException
, std::exception
)
410 MutexGuard
aGuard( m_aMutex
);
411 // We do not need to adapt the SQL for Firebird atm.
415 void SAL_CALL
Connection::setAutoCommit( sal_Bool autoCommit
)
416 throw(SQLException
, RuntimeException
, std::exception
)
418 MutexGuard
aGuard( m_aMutex
);
419 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
421 m_bIsAutoCommit
= autoCommit
;
423 if (m_aTransactionHandle
)
429 sal_Bool SAL_CALL
Connection::getAutoCommit() throw(SQLException
, RuntimeException
, std::exception
)
431 MutexGuard
aGuard( m_aMutex
);
432 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
434 return m_bIsAutoCommit
;
437 void Connection::setupTransaction()
440 MutexGuard
aGuard( m_aMutex
);
441 ISC_STATUS status_vector
[20];
443 // TODO: is this sensible? If we have changed parameters then transaction
445 if (m_aTransactionHandle
)
448 isc_rollback_transaction(status_vector
, &m_aTransactionHandle
);
451 char aTransactionIsolation
= 0;
452 switch (m_aTransactionIsolation
)
454 // TODO: confirm that these are correct.
455 case(TransactionIsolation::READ_UNCOMMITTED
):
456 aTransactionIsolation
= isc_tpb_concurrency
;
458 case(TransactionIsolation::READ_COMMITTED
):
459 aTransactionIsolation
= isc_tpb_read_committed
;
461 case(TransactionIsolation::REPEATABLE_READ
):
462 aTransactionIsolation
= isc_tpb_consistency
;
464 case(TransactionIsolation::SERIALIZABLE
):
465 aTransactionIsolation
= isc_tpb_consistency
;
468 assert( false ); // We must have a valid TransactionIsolation.
471 // You cannot pass an empty tpb parameter so we have to do some pointer
472 // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
476 *pTPB
++ = isc_tpb_version3
;
478 *pTPB
++ = isc_tpb_autocommit
;
479 *pTPB
++ = (!m_bIsReadOnly
? isc_tpb_write
: isc_tpb_read
);
480 *pTPB
++ = aTransactionIsolation
;
481 *pTPB
++ = isc_tpb_wait
;
483 isc_start_transaction(status_vector
,
484 &m_aTransactionHandle
,
487 pTPB
- aTPB
, // bytes used in TPB
490 evaluateStatusVector(status_vector
,
491 "isc_start_transaction",
495 isc_tr_handle
& Connection::getTransaction()
498 MutexGuard
aGuard( m_aMutex
);
499 if (!m_aTransactionHandle
)
503 return m_aTransactionHandle
;
506 void SAL_CALL
Connection::commit() throw(SQLException
, RuntimeException
, std::exception
)
508 MutexGuard
aGuard( m_aMutex
);
509 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
511 ISC_STATUS status_vector
[20];
513 if (!m_bIsAutoCommit
&& m_aTransactionHandle
)
516 isc_commit_transaction(status_vector
, &m_aTransactionHandle
);
517 evaluateStatusVector(status_vector
,
518 "isc_commit_transaction",
523 void SAL_CALL
Connection::rollback() throw(SQLException
, RuntimeException
, std::exception
)
525 MutexGuard
aGuard( m_aMutex
);
526 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
528 ISC_STATUS status_vector
[20];
530 if (!m_bIsAutoCommit
&& m_aTransactionHandle
)
532 isc_rollback_transaction(status_vector
, &m_aTransactionHandle
);
536 sal_Bool SAL_CALL
Connection::isClosed( ) throw(SQLException
, RuntimeException
, std::exception
)
538 MutexGuard
aGuard( m_aMutex
);
540 // just simple -> we are close when we are disposed taht means someone called dispose(); (XComponent)
541 return Connection_BASE::rBHelper
.bDisposed
;
544 Reference
< XDatabaseMetaData
> SAL_CALL
Connection::getMetaData( ) throw(SQLException
, RuntimeException
, std::exception
)
546 MutexGuard
aGuard( m_aMutex
);
547 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
549 // here we have to create the class with biggest interface
550 // The answer is 42 :-)
551 Reference
< XDatabaseMetaData
> xMetaData
= m_xMetaData
;
554 xMetaData
= new ODatabaseMetaData(this); // need the connection because it can return it
555 m_xMetaData
= xMetaData
;
561 void SAL_CALL
Connection::setReadOnly(sal_Bool readOnly
)
562 throw(SQLException
, RuntimeException
, std::exception
)
564 MutexGuard
aGuard( m_aMutex
);
565 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
567 m_bIsReadOnly
= readOnly
;
571 sal_Bool SAL_CALL
Connection::isReadOnly() throw(SQLException
, RuntimeException
, std::exception
)
573 MutexGuard
aGuard( m_aMutex
);
574 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
576 return m_bIsReadOnly
;
579 void SAL_CALL
Connection::setCatalog(const OUString
& /*catalog*/)
580 throw(SQLException
, RuntimeException
, std::exception
)
582 ::dbtools::throwFunctionNotSupportedException("setCatalog", *this);
585 OUString SAL_CALL
Connection::getCatalog()
586 throw(SQLException
, RuntimeException
, std::exception
)
588 ::dbtools::throwFunctionNotSupportedException("getCatalog", *this);
592 void SAL_CALL
Connection::setTransactionIsolation( sal_Int32 level
) throw(SQLException
, RuntimeException
, std::exception
)
594 MutexGuard
aGuard( m_aMutex
);
595 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
597 m_aTransactionIsolation
= level
;
601 sal_Int32 SAL_CALL
Connection::getTransactionIsolation( ) throw(SQLException
, RuntimeException
, std::exception
)
603 MutexGuard
aGuard( m_aMutex
);
604 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
606 return m_aTransactionIsolation
;
609 Reference
< XNameAccess
> SAL_CALL
Connection::getTypeMap() throw(SQLException
, RuntimeException
, std::exception
)
611 ::dbtools::throwFeatureNotImplementedException( "XConnection::getTypeMap", *this );
615 void SAL_CALL
Connection::setTypeMap(const Reference
< XNameAccess
>& typeMap
)
616 throw(SQLException
, RuntimeException
, std::exception
)
618 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
622 //----- XCloseable -----------------------------------------------------------
623 void SAL_CALL
Connection::close( ) throw(SQLException
, RuntimeException
, std::exception
)
625 // we just dispose us
627 MutexGuard
aGuard( m_aMutex
);
628 checkDisposed(Connection_BASE::rBHelper
.bDisposed
);
635 Any SAL_CALL
Connection::getWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
637 // when you collected some warnings -> return it
641 void SAL_CALL
Connection::clearWarnings( ) throw(SQLException
, RuntimeException
, std::exception
)
643 // you should clear your collected warnings here
646 // XDocumentEventListener
647 void SAL_CALL
Connection::documentEventOccured( const DocumentEvent
& _Event
)
648 throw(RuntimeException
, std::exception
)
650 MutexGuard
aGuard(m_aMutex
);
655 if (_Event
.EventName
== "OnSave" || _Event
.EventName
== "OnSaveAs")
657 commit(); // Commit and close transaction
658 if ( m_bIsEmbedded
&& m_xEmbeddedStorage
.is() )
660 SAL_INFO("connectivity.firebird", "Writing .fdb into .odb" );
662 Reference
< XStream
> xDBStream(m_xEmbeddedStorage
->openStreamElement(our_sDBLocation
,
663 ElementModes::WRITE
));
665 using namespace ::comphelper
;
666 Reference
< XComponentContext
> xContext
= comphelper::getProcessComponentContext();
667 Reference
< XInputStream
> xInputStream
;
670 OStorageHelper::GetInputStreamFromURL(m_sFirebirdURL
, xContext
);
671 if (xInputStream
.is())
672 OStorageHelper::CopyInputToOutput( xInputStream
,
673 xDBStream
->getOutputStream());
674 // TODO: ensure db is in safe state
679 void SAL_CALL
Connection::disposing(const EventObject
& /*rSource*/)
680 throw (RuntimeException
, std::exception
)
684 void Connection::buildTypeInfo() throw( SQLException
)
686 MutexGuard
aGuard( m_aMutex
);
688 Reference
< XResultSet
> xRs
= getMetaData ()->getTypeInfo ();
689 Reference
< XRow
> xRow(xRs
,UNO_QUERY
);
690 // Information for a single SQL type
692 // Loop on the result set until we reach end of file
697 aInfo
.aTypeName
= xRow
->getString (1);
698 aInfo
.nType
= xRow
->getShort (2);
699 aInfo
.nPrecision
= xRow
->getInt (3);
700 aInfo
.aLiteralPrefix
= xRow
->getString (4);
701 aInfo
.aLiteralSuffix
= xRow
->getString (5);
702 aInfo
.aCreateParams
= xRow
->getString (6);
703 aInfo
.bNullable
= xRow
->getBoolean (7) == ColumnValue::NULLABLE
;
704 aInfo
.bCaseSensitive
= xRow
->getBoolean (8);
705 aInfo
.nSearchType
= xRow
->getShort (9);
706 aInfo
.bUnsigned
= xRow
->getBoolean (10);
707 aInfo
.bCurrency
= xRow
->getBoolean (11);
708 aInfo
.bAutoIncrement
= xRow
->getBoolean (12);
709 aInfo
.aLocalTypeName
= xRow
->getString (13);
710 aInfo
.nMinimumScale
= xRow
->getShort (14);
711 aInfo
.nMaximumScale
= xRow
->getShort (15);
712 aInfo
.nNumPrecRadix
= (sal_Int16
)xRow
->getInt(18);
716 // Now that we have the type info, save it
717 // in the Hashtable if we don't already have an
718 // entry for this SQL type.
720 m_aTypeInfo
.push_back(aInfo
);
723 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
726 // Close the result set/statement.
728 Reference
< XCloseable
> xClose(xRs
,UNO_QUERY
);
731 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
735 void Connection::disposing()
737 MutexGuard
aGuard(m_aMutex
);
741 m_xMetaData
= ::com::sun::star::uno::WeakReference
< ::com::sun::star::sdbc::XDatabaseMetaData
>();
743 ISC_STATUS_ARRAY status
; /* status vector */
744 if (m_aTransactionHandle
)
746 // TODO: confirm whether we need to ask the user here.
747 isc_rollback_transaction(status
, &m_aTransactionHandle
);
750 if (isc_detach_database(status
, &m_aDBHandle
))
752 evaluateStatusVector(status
, "isc_detach_database", *this);
754 // TODO: write to storage again?
757 cppu::WeakComponentImplHelperBase::disposing();
760 void Connection::disposeStatements()
762 MutexGuard
aGuard(m_aMutex
);
763 for (OWeakRefArray::iterator i
= m_aStatements
.begin(); m_aStatements
.end() != i
; ++i
)
765 Reference
< XComponent
> xComp(i
->get(), UNO_QUERY
);
769 m_aStatements
.clear();
772 uno::Reference
< XTablesSupplier
> Connection::createCatalog()
774 MutexGuard
aGuard(m_aMutex
);
776 // m_xCatalog is a weak reference. Reuse it if it still exists.
777 Reference
< XTablesSupplier
> xCatalog
= m_xCatalog
;
784 xCatalog
= new Catalog(this);
785 m_xCatalog
= xCatalog
;
791 void Connection::rebuildIndexes() throw(SQLException
)
793 MutexGuard
aGuard(m_aMutex
);
795 // We only need to do this for character based columns on user-created tables.
797 // Ideally we'd use a FOR SELECT ... INTO .... DO ..., but that seems to
798 // only be possible using PSQL, i.e. using a stored procedure.
800 // multiple columns possible per index, only select once
801 "SELECT DISTINCT indices.RDB$INDEX_NAME "
802 "FROM RDB$INDICES indices "
803 "JOIN RDB$INDEX_SEGMENTS index_segments "
804 "ON (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) "
805 "JOIN RDB$RELATION_FIELDS relation_fields "
806 "ON (index_segments.RDB$FIELD_NAME = relation_fields.RDB$FIELD_NAME) "
807 "JOIN RDB$FIELDS fields "
808 "ON (relation_fields.RDB$FIELD_SOURCE = fields.RDB$FIELD_NAME) "
810 "WHERE (indices.RDB$SYSTEM_FLAG = 0) "
811 // TODO: what about blr_text2 etc. ?
812 "AND ((fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_text
) + ") "
813 " OR (fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_varying
) + ")) "
814 "AND (indices.RDB$INDEX_INACTIVE IS NULL OR indices.RDB$INDEX_INACTIVE = 0) "
817 uno::Reference
< XStatement
> xCharIndicesStatement
= createStatement();
818 uno::Reference
< XResultSet
> xCharIndices
=
819 xCharIndicesStatement
->executeQuery(sSql
);
820 uno::Reference
< XRow
> xRow(xCharIndices
, UNO_QUERY_THROW
);
822 uno::Reference
< XStatement
> xAlterIndexStatement
= createStatement();
824 // ALTER is a DDL statement, hence using Statement will cause a commit
825 // after every alter -- in this case this is inappropriate (xCharIndicesStatement
826 // and its ResultSet become invalidated) hence we use the native api.
827 while (xCharIndices
->next())
829 OUString
sIndexName(sanitizeIdentifier(xRow
->getString(1)));
830 SAL_INFO("connectivity.firebird", "rebuilding index " + sIndexName
);
831 OString sAlterIndex
= "ALTER INDEX \""
832 + OUStringToOString(sIndexName
, RTL_TEXTENCODING_UTF8
)
835 ISC_STATUS_ARRAY aStatusVector
;
838 aErr
= isc_dsql_execute_immediate(aStatusVector
,
841 0, // Length: 0 for null terminated
842 sAlterIndex
.getStr(),
843 FIREBIRD_SQL_DIALECT
,
846 evaluateStatusVector(aStatusVector
,
847 "rebuildIndexes:isc_dsql_execute_immediate",
852 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */