Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / firebird / Connection.cxx
blob53349ee53cb7283820d75224d7c5b9b312850d3b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "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"
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)
80 , m_pDriver(_pDriver)
81 , m_sConnectionURL()
82 , m_sFirebirdURL()
83 , m_bIsEmbedded(false)
84 , m_xEmbeddedStorage(0)
85 , m_bIsFile(false)
86 , m_sUser()
87 , m_bIsAutoCommit(false)
88 , m_bIsReadOnly(false)
89 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
90 , m_aDBHandle(0)
91 , m_aTransactionHandle(0)
92 , m_xCatalog(0)
93 , m_xMetaData(0)
94 , m_aStatements()
96 m_pDriver->acquire();
99 Connection::~Connection()
101 if(!isClosed())
102 close();
104 m_pDriver->release();
105 m_pDriver = 0;
108 void SAL_CALL Connection::release() throw()
110 relase_ChildImpl();
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);
160 if (!bIsNewDatabase)
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() ),
175 uno::UNO_QUERY );
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://"))
194 m_bIsFile = true;
195 uno::Reference< ucb::XSimpleFileAccess > xFileAccess(
196 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()),
197 uno::UNO_QUERY);
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
206 int dpbLength = 0;
208 char* dpb;
209 char userName[256] = "";
210 char userPassword[256] = "";
212 dpb = dpbBuffer;
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
224 *dpb++ = 1; // TRUE
226 else
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 */
253 ISC_STATUS aErr;
254 if (bIsNewDatabase)
256 aErr = isc_create_database(status,
257 m_sFirebirdURL.getLength(),
258 OUStringToOString(m_sFirebirdURL,RTL_TEXTENCODING_UTF8).getStr(),
259 &m_aDBHandle,
260 dpbLength,
261 dpbBuffer,
263 if (aErr)
265 evaluateStatusVector(status, "isc_create_database", *this);
268 else
270 aErr = isc_attach_database(status,
271 m_sFirebirdURL.getLength(),
272 OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8).getStr(),
273 &m_aDBHandle,
274 dpbLength,
275 dpbBuffer);
276 if (aErr)
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
287 // it in the .odb.
288 rebuildIndexes();
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);
296 else
297 assert(false);
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,
321 *pBlobId);
323 m_aStatements.push_back(WeakReferenceHelper(xReturn));
324 return 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);
335 // the pre
336 if(m_aTypeInfo.empty())
337 buildTypeInfo();
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));
343 return xReturn;
346 OUString Connection::transformPreparedStatement(const OUString& _sSQL)
348 OUString sSqlStatement (_sSQL);
351 OSQLParser aParser( m_pDriver->getContext() );
352 OUString sErrorMessage;
353 OUString sNewSql;
354 OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
355 if(pNode)
356 { // special handling for parameters
357 OSQLParseNode::substituteParameterNames(pNode);
358 pNode->parseNodeToStr( sNewSql, this );
359 delete pNode;
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())
380 buildTypeInfo();
382 OUString sSqlStatement (transformPreparedStatement( _sSql ));
384 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,
385 m_aTypeInfo,
386 sSqlStatement);
387 m_aStatements.push_back(WeakReferenceHelper(xReturn));
389 return xReturn;
392 Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
393 const OUString& _sSql ) throw(SQLException, RuntimeException, std::exception)
395 SAL_INFO("connectivity.firebird", "prepareCall(). "
396 "_sSql: " << _sSql);
398 MutexGuard aGuard( m_aMutex );
399 checkDisposed(Connection_BASE::rBHelper.bDisposed);
401 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
403 // not implemented yet :-) a task to do
404 return NULL;
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.
412 return _sSql;
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)
425 setupTransaction();
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()
438 throw (SQLException)
440 MutexGuard aGuard( m_aMutex );
441 ISC_STATUS status_vector[20];
443 // TODO: is this sensible? If we have changed parameters then transaction
444 // is lost...
445 if (m_aTransactionHandle)
447 disposeStatements();
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;
457 break;
458 case(TransactionIsolation::READ_COMMITTED):
459 aTransactionIsolation = isc_tpb_read_committed;
460 break;
461 case(TransactionIsolation::REPEATABLE_READ):
462 aTransactionIsolation = isc_tpb_consistency;
463 break;
464 case(TransactionIsolation::SERIALIZABLE):
465 aTransactionIsolation = isc_tpb_consistency;
466 break;
467 default:
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)
473 char aTPB[5];
474 char* pTPB = aTPB;
476 *pTPB++ = isc_tpb_version3;
477 if (m_bIsAutoCommit)
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,
486 &m_aDBHandle,
487 pTPB - aTPB, // bytes used in TPB
488 aTPB);
490 evaluateStatusVector(status_vector,
491 "isc_start_transaction",
492 *this);
495 isc_tr_handle& Connection::getTransaction()
496 throw (SQLException)
498 MutexGuard aGuard( m_aMutex );
499 if (!m_aTransactionHandle)
501 setupTransaction();
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)
515 disposeStatements();
516 isc_commit_transaction(status_vector, &m_aTransactionHandle);
517 evaluateStatusVector(status_vector,
518 "isc_commit_transaction",
519 *this);
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;
552 if(!xMetaData.is())
554 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
555 m_xMetaData = xMetaData;
558 return 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;
568 setupTransaction();
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);
589 return OUString();
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;
598 setupTransaction();
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 );
612 return 0;
615 void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >& typeMap)
616 throw(SQLException, RuntimeException, std::exception)
618 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
619 (void) typeMap;
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);
631 dispose();
634 // XWarningsSupplier
635 Any SAL_CALL Connection::getWarnings( ) throw(SQLException, RuntimeException, std::exception)
637 // when you collected some warnings -> return it
638 return Any();
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);
652 if (!m_bIsEmbedded)
653 return;
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;
668 if (xContext.is())
669 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
678 // XEventListener
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
694 while (xRs->next ())
696 OTypeInfo aInfo;
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(). "
724 "Type info built.");
726 // Close the result set/statement.
728 Reference< XCloseable> xClose(xRs,UNO_QUERY);
729 xClose->close();
731 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
732 "Closed.");
735 void Connection::disposing()
737 MutexGuard aGuard(m_aMutex);
739 disposeStatements();
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?
756 dispose_ChildImpl();
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);
766 if (xComp.is())
767 xComp->dispose();
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;
778 if (xCatalog.is())
780 return xCatalog;
782 else
784 xCatalog = new Catalog(this);
785 m_xCatalog = xCatalog;
786 return m_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.
799 OUString sSql(
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)
833 + "\" ACTIVE";
835 ISC_STATUS_ARRAY aStatusVector;
836 ISC_STATUS aErr;
838 aErr = isc_dsql_execute_immediate(aStatusVector,
839 &getDBHandle(),
840 &getTransaction(),
841 0, // Length: 0 for null terminated
842 sAlterIndex.getStr(),
843 FIREBIRD_SQL_DIALECT,
844 NULL);
845 if (aErr)
846 evaluateStatusVector(aStatusVector,
847 "rebuildIndexes:isc_dsql_execute_immediate",
848 *this);
850 commit();
852 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */