LibreOffice Module connectivity (master) 1
Connection.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2/*
3 * This file is part of the LibreOffice project.
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 "Blob.hxx"
21#include "Catalog.hxx"
22#include "Clob.hxx"
23#include "Connection.hxx"
24#include "DatabaseMetaData.hxx"
25#include "PreparedStatement.hxx"
26#include "Statement.hxx"
27#include "Util.hxx"
28
29#include <stdexcept>
30
31#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
32#include <com/sun/star/embed/ElementModes.hpp>
33#include <com/sun/star/io/XStream.hpp>
34#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
35#include <com/sun/star/sdbc/SQLException.hpp>
36#include <com/sun/star/sdbc/XRow.hpp>
37#include <com/sun/star/sdbc/TransactionIsolation.hpp>
38#include <com/sun/star/ucb/SimpleFileAccess.hpp>
39#include <com/sun/star/ucb/XSimpleFileAccess2.hpp>
40
42#include <strings.hrc>
44
49#include <unotools/tempfile.hxx>
50
51#include <osl/file.hxx>
52#include <rtl/strbuf.hxx>
53#include <sal/log.hxx>
54
55using namespace connectivity::firebird;
56using namespace connectivity;
57
58using namespace ::osl;
59
60using namespace ::com::sun::star;
61using namespace ::com::sun::star::beans;
62using namespace ::com::sun::star::container;
63using namespace ::com::sun::star::document;
64using namespace ::com::sun::star::embed;
65using namespace ::com::sun::star::io;
66using namespace ::com::sun::star::lang;
67using namespace ::com::sun::star::sdbc;
68using namespace ::com::sun::star::sdbcx;
69using namespace ::com::sun::star::uno;
70
75constexpr OUStringLiteral our_sFDBLocation( u"firebird.fdb" );
79constexpr OUStringLiteral our_sFBKLocation( u"firebird.fbk" );
80
81Connection::Connection()
83 , m_bIsEmbedded(false)
84 , m_bIsFile(false)
85 , m_bIsAutoCommit(true)
86 , m_bIsReadOnly(false)
87 , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ)
88#if SAL_TYPES_SIZEOFPOINTER == 8
89 , m_aDBHandle(0)
90 , m_aTransactionHandle(0)
91#else
92 , m_aDBHandle(nullptr)
93 , m_aTransactionHandle(nullptr)
94#endif
95 , m_xCatalog(nullptr)
96 , m_xMetaData(nullptr)
97{
98}
99
101{
102 if(!isClosed())
103 close();
104}
105
106namespace {
107
108struct ConnectionGuard
109{
110 oslInterlockedCount& m_refCount;
111 explicit ConnectionGuard(oslInterlockedCount& refCount)
112 : m_refCount(refCount)
113 {
114 osl_atomic_increment(&m_refCount);
115 }
116 ~ConnectionGuard()
117 {
118 osl_atomic_decrement(&m_refCount);
119 }
120};
121
122}
123
124void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info)
125{
126 ConnectionGuard aGuard(m_refCount);
127
128 try
129 {
130 m_sConnectionURL = url;
131
132 bool bIsNewDatabase = false;
133 // the database may be stored as an
134 // fdb file in older versions
135 bool bIsFdbStored = false;
136 if (url == "sdbc:embedded:firebird")
137 {
138 m_bIsEmbedded = true;
139
140 const PropertyValue* pIter = info.getConstArray();
141 const PropertyValue* pEnd = pIter + info.getLength();
142
143 for (;pIter != pEnd; ++pIter)
144 {
145 if ( pIter->Name == "Storage" )
146 {
147 m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY);
148 }
149 else if ( pIter->Name == "Document" )
150 {
151 pIter->Value >>= m_xParentDocument;
152 }
153 }
154
155 if ( !m_xEmbeddedStorage.is() )
156 {
158 const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE);
160 }
161
162 bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
163
164 m_pDatabaseFileDir.reset(new ::utl::TempFileNamed(nullptr, true));
165 m_pDatabaseFileDir->EnableKillingFile();
166 m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
167 m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
168
169 SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL);
170
171 if (!bIsNewDatabase)
172 {
173 if (m_xEmbeddedStorage->hasByName(our_sFBKLocation) &&
174 m_xEmbeddedStorage->isStreamElement(our_sFBKLocation))
175 {
176 SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" );
178 }
179 else if(m_xEmbeddedStorage->hasByName(our_sFDBLocation) &&
180 m_xEmbeddedStorage->isStreamElement(our_sFDBLocation))
181 {
182 SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk");
183 bIsFdbStored = true;
185 }
186 else
187 {
188 // There might be files which are not firebird databases.
189 // This is not a problem.
190 bIsNewDatabase = true;
191 }
192 }
193 // TODO: Get DB properties from XML
194
195 }
196 // External file AND/OR remote connection
197 else if (url.startsWith("sdbc:firebird:"))
198 {
199 m_sFirebirdURL = url.copy(strlen("sdbc:firebird:"));
200 if (m_sFirebirdURL.startsWith("file://"))
201 {
202 m_bIsFile = true;
203 uno::Reference< ucb::XSimpleFileAccess > xFileAccess =
204 ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext());
205 if (!xFileAccess->exists(m_sFirebirdURL))
206 bIsNewDatabase = true;
207
208 osl::FileBase::getSystemPathFromFileURL(m_sFirebirdURL, m_sFirebirdURL);
209 }
210 }
211
212 std::string dpbBuffer;
213 {
214 OString userName;
215 OString userPassword;
216
217 dpbBuffer.push_back(isc_dpb_version1);
218 dpbBuffer.push_back(isc_dpb_sql_dialect);
219 dpbBuffer.push_back(1); // 1 byte long
220 dpbBuffer.push_back(SQL_DIALECT_CURRENT);
221
222 // set UTF8 as default character set of the database
223 const char sCharset[] = "UTF8";
224 dpbBuffer.push_back(isc_dpb_set_db_charset);
225 dpbBuffer.push_back(sizeof(sCharset) - 1);
226 dpbBuffer.append(sCharset);
227 // set UTF8 as default character set of the connection
228 dpbBuffer.push_back(isc_dpb_lc_ctype);
229 dpbBuffer.push_back(sizeof(sCharset) - 1);
230 dpbBuffer.append(sCharset);
231
232 // Do any more dpbBuffer additions here
233
235 {
236 userName = "sysdba";
237 userPassword = "masterkey";
238 }
239 else
240 {
241 for (const auto& rIter : info)
242 {
243 if (rIter.Name == "user")
244 {
245 if (OUString value; rIter.Value >>= value)
246 userName = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
247 }
248 else if (rIter.Name == "password")
249 {
250 if (OUString value; rIter.Value >>= value)
251 userPassword = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
252 }
253 }
254 }
255
256 if (!userName.isEmpty())
257 {
258 const sal_Int32 nMaxUsername = 255; //max size
259 int nUsernameLength = std::min(userName.getLength(), nMaxUsername);
260 dpbBuffer.push_back(isc_dpb_user_name);
261 dpbBuffer.push_back(nUsernameLength);
262 dpbBuffer.append(userName.getStr(), nUsernameLength);
263 }
264
265 if (!userPassword.isEmpty())
266 {
267 const sal_Int32 nMaxPassword = 255; //max size
268 int nPasswordLength = std::min(userPassword.getLength(), nMaxPassword);
269 dpbBuffer.push_back(isc_dpb_password);
270 dpbBuffer.push_back(nPasswordLength);
271 dpbBuffer.append(userPassword.getStr(), nPasswordLength);
272 }
273 }
274
275 // use isc_dpb_utf8_filename to identify encoding of filenames
276 dpbBuffer.push_back(isc_dpb_utf8_filename);
277 dpbBuffer.push_back(0); // no filename here, it is passed to functions directly
278
279 ISC_STATUS_ARRAY status; /* status vector */
280 ISC_STATUS aErr;
281 const OString sFirebirdURL = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
282 if (bIsNewDatabase)
283 {
284 aErr = isc_create_database(status,
285 sFirebirdURL.getLength(),
286 sFirebirdURL.getStr(),
288 dpbBuffer.size(),
289 dpbBuffer.c_str(),
290 0);
291 if (aErr)
292 {
293 evaluateStatusVector(status, u"isc_create_database", *this);
294 }
295 }
296 else
297 {
298 if (m_bIsEmbedded && !bIsFdbStored) // We need to restore the .fbk first
299 {
300 runBackupService(isc_action_svc_restore);
301 }
302
303 aErr = isc_attach_database(status,
304 sFirebirdURL.getLength(),
305 sFirebirdURL.getStr(),
307 dpbBuffer.size(),
308 dpbBuffer.c_str());
309 if (aErr)
310 {
311 evaluateStatusVector(status, u"isc_attach_database", *this);
312 }
313 }
314
315 if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed
316 {
317 // We need to attach as a document listener in order to be able to store
318 // the temporary db back into the .odb when saving
319 uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY);
320
321 if (xBroadcaster.is())
322 xBroadcaster->addDocumentEventListener(this);
323 else
324 assert(false);
325 }
326 }
327 catch (const Exception&)
328 {
329 throw;
330 }
331 catch (const std::exception&)
332 {
333 throw;
334 }
335 catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it
336
337 {
338 throw std::runtime_error("Generic Firebird::Exception");
339 }
340}
341
342
343//----- XServiceInfo ---------------------------------------------------------
344IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection",
345 "com.sun.star.sdbc.Connection")
346
347Reference< XBlob> Connection::createBlob(ISC_QUAD const * pBlobId)
348{
349 MutexGuard aGuard(m_aMutex);
350 checkDisposed(Connection_BASE::rBHelper.bDisposed);
351
352 Reference< XBlob > xReturn = new Blob(&m_aDBHandle,
353 &m_aTransactionHandle,
354 *pBlobId);
355
356 m_aStatements.push_back(WeakReferenceHelper(xReturn));
357 return xReturn;
358}
359
360Reference< XClob> Connection::createClob(ISC_QUAD const * pBlobId)
361{
362 MutexGuard aGuard(m_aMutex);
363 checkDisposed(Connection_BASE::rBHelper.bDisposed);
364
365 Reference< XClob > xReturn = new Clob(&m_aDBHandle,
367 *pBlobId);
368
369 m_aStatements.push_back(WeakReferenceHelper(xReturn));
370 return xReturn;
371}
372
373//----- XUnoTunnel ----------------------------------------------------------
374// virtual
375sal_Int64 SAL_CALL Connection::getSomething(const css::uno::Sequence<sal_Int8>& rId)
376{
377 return comphelper::getSomethingImpl(rId, this);
378}
379
380// static
381const css::uno::Sequence<sal_Int8> & Connection::getUnoTunnelId()
382{
383 static const comphelper::UnoIdInit implId;
384 return implId.getSeq();
385}
386
387//----- XConnection ----------------------------------------------------------
388Reference< XStatement > SAL_CALL Connection::createStatement( )
389{
390 MutexGuard aGuard( m_aMutex );
391 checkDisposed(Connection_BASE::rBHelper.bDisposed);
392
393 // the pre
394 if(m_aTypeInfo.empty())
396
397 // create a statement
398 // the statement can only be executed once
399 Reference< XStatement > xReturn = new OStatement(this);
400 m_aStatements.push_back(WeakReferenceHelper(xReturn));
401 return xReturn;
402}
403
404Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement(
405 const OUString& _sSql)
406{
407 SAL_INFO("connectivity.firebird", "prepareStatement() "
408 "called with sql: " << _sSql);
409 MutexGuard aGuard(m_aMutex);
410 checkDisposed(Connection_BASE::rBHelper.bDisposed);
411
412 if(m_aTypeInfo.empty())
414
415 Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql);
416 m_aStatements.push_back(WeakReferenceHelper(xReturn));
417
418 return xReturn;
419}
420
421Reference< XPreparedStatement > SAL_CALL Connection::prepareCall(
422 const OUString& _sSql )
423{
424 SAL_INFO("connectivity.firebird", "prepareCall(). "
425 "_sSql: " << _sSql);
426
427 MutexGuard aGuard( m_aMutex );
428 checkDisposed(Connection_BASE::rBHelper.bDisposed);
429
430 // OUString sSqlStatement (transformPreparedStatement( _sSql ));
431
432 // not implemented yet :-) a task to do
433 return nullptr;
434}
435
436OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql )
437{
438 // We do not need to adapt the SQL for Firebird atm.
439 return _sSql;
440}
441
442void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit )
443{
444 MutexGuard aGuard( m_aMutex );
445 checkDisposed(Connection_BASE::rBHelper.bDisposed);
446
447 m_bIsAutoCommit = autoCommit;
448
450 {
452 }
453}
454
456{
457 MutexGuard aGuard( m_aMutex );
458 checkDisposed(Connection_BASE::rBHelper.bDisposed);
459
460 return m_bIsAutoCommit;
461}
462
464{
465 MutexGuard aGuard( m_aMutex );
466 ISC_STATUS status_vector[20];
467
468 // TODO: is this sensible? If we have changed parameters then transaction
469 // is lost...
471 {
473 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
474 }
475
476 char aTransactionIsolation = 0;
478 {
479 // TODO: confirm that these are correct.
480 case TransactionIsolation::READ_UNCOMMITTED:
481 aTransactionIsolation = isc_tpb_concurrency;
482 break;
483 case TransactionIsolation::READ_COMMITTED:
484 aTransactionIsolation = isc_tpb_read_committed;
485 break;
486 case TransactionIsolation::REPEATABLE_READ:
487 aTransactionIsolation = isc_tpb_consistency;
488 break;
489 case TransactionIsolation::SERIALIZABLE:
490 aTransactionIsolation = isc_tpb_consistency;
491 break;
492 default:
493 assert( false ); // We must have a valid TransactionIsolation.
494 }
495
496 // You cannot pass an empty tpb parameter so we have to do some pointer
497 // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid)
498 char aTPB[5];
499 char* pTPB = aTPB;
500
501 *pTPB++ = isc_tpb_version3;
502 if (m_bIsAutoCommit)
503 *pTPB++ = isc_tpb_autocommit;
504 *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read);
505 *pTPB++ = aTransactionIsolation;
506 *pTPB++ = isc_tpb_wait;
507
508 isc_start_transaction(status_vector,
510 1,
512 pTPB - aTPB, // bytes used in TPB
513 aTPB);
514
515 evaluateStatusVector(status_vector,
516 u"isc_start_transaction",
517 *this);
518}
519
521{
522 MutexGuard aGuard( m_aMutex );
524 {
526 }
528}
529
530void SAL_CALL Connection::commit()
531{
532 MutexGuard aGuard( m_aMutex );
533 checkDisposed(Connection_BASE::rBHelper.bDisposed);
534
535 ISC_STATUS status_vector[20];
536
538 {
540 isc_commit_transaction(status_vector, &m_aTransactionHandle);
541 evaluateStatusVector(status_vector,
542 u"isc_commit_transaction",
543 *this);
544 }
545}
546
547void Connection::loadDatabaseFile(const OUString& srcLocation, const OUString& tmpLocation)
548{
549 Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(srcLocation,
550 ElementModes::READ));
551
552 uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess =
553 ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
554 if ( !xFileAccess.is() )
555 {
557 // TODO FIXME: this does _not_ look like the right error message
558 const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
560 }
561 xFileAccess->writeFile(tmpLocation,xDBStream->getInputStream());
562}
563
565{
566 ISC_STATUS_ARRAY aStatusVector;
567#if SAL_TYPES_SIZEOFPOINTER == 8
568 isc_svc_handle aServiceHandle = 0;
569#else
570 isc_svc_handle aServiceHandle = nullptr;
571#endif
572
573 char aSPBBuffer[256];
574 char* pSPB = aSPBBuffer;
575 *pSPB++ = isc_spb_version;
576 *pSPB++ = isc_spb_current_version;
577 *pSPB++ = isc_spb_user_name;
578 OUString sUserName("SYSDBA");
579 char aLength = static_cast<char>(sUserName.getLength());
580 *pSPB++ = aLength;
581 strncpy(pSPB,
582 OUStringToOString(sUserName,
583 RTL_TEXTENCODING_UTF8).getStr(),
584 aLength);
585 pSPB += aLength;
586 // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ...
587 if (isc_service_attach(aStatusVector,
588 0, // Denotes null-terminated string next
589 "service_mgr",
590 &aServiceHandle,
591 pSPB - aSPBBuffer,
592 aSPBBuffer))
593 {
594 evaluateStatusVector(aStatusVector,
595 u"isc_service_attach",
596 *this);
597 }
598
599 return aServiceHandle;
600}
601
602void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
603{
604 ISC_STATUS_ARRAY aStatusVector;
605 if (isc_service_detach(aStatusVector,
606 &aServiceHandle))
607 {
608 evaluateStatusVector(aStatusVector,
609 u"isc_service_detach",
610 *this);
611 }
612}
613
614void Connection::runBackupService(const short nAction)
615{
616 assert(nAction == isc_action_svc_backup
617 || nAction == isc_action_svc_restore);
618
619 ISC_STATUS_ARRAY aStatusVector;
620
621 // convert paths to 8-Bit strings
622 OString sFDBPath = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8);
623 OString sFBKPath = OUStringToOString(m_sFBKPath, RTL_TEXTENCODING_UTF8);
624
625
626 sal_uInt16 nFDBLength = sFDBPath.getLength();
627 sal_uInt16 nFBKLength = sFBKPath.getLength();
628 OStringBuffer aRequest( // byte array
629 OStringChar(static_cast<char>(nAction))
630 + OStringChar(char(isc_spb_dbname)) // .fdb
631 + OStringChar(static_cast<char>(nFDBLength & 0xFF)) // least significant byte first
632 + OStringChar(static_cast<char>((nFDBLength >> 8) & 0xFF))
633 + sFDBPath
634 + OStringChar(char(isc_spb_bkp_file)) // .fbk
635 + OStringChar(static_cast<char>(nFBKLength & 0xFF))
636 + OStringChar(static_cast<char>((nFBKLength >> 8) & 0xFF))
637 + sFBKPath);
638
639 if (nAction == isc_action_svc_restore)
640 {
641 aRequest.append(char(isc_spb_options)); // 4-Byte bitmask
642 char sOptions[4];
643 char * pOptions = sOptions;
644#ifdef _WIN32
645#pragma warning(push)
646#pragma warning(disable: 4310) // cast truncates data
647#endif
648 ADD_SPB_NUMERIC(pOptions, isc_spb_res_create);
649#ifdef _WIN32
650#pragma warning(pop)
651#endif
652 aRequest.append(sOptions, 4);
653 }
654
655 isc_svc_handle aServiceHandle;
656 aServiceHandle = attachServiceManager();
657
658 if (isc_service_start(aStatusVector,
659 &aServiceHandle,
660 nullptr,
661 aRequest.getLength(),
662 aRequest.getStr()))
663 {
664 evaluateStatusVector(aStatusVector, u"isc_service_start", *this);
665 }
666
667 char aInfoSPB = isc_info_svc_line;
668 char aResults[256];
669
670 // query blocks until success or error
671 if(isc_service_query(aStatusVector,
672 &aServiceHandle,
673 nullptr, // Reserved null
674 0,nullptr, // "send" spb -- size and spb -- not needed?
675 1,
676 &aInfoSPB,
677 sizeof(aResults),
678 aResults))
679 {
680 evaluateStatusVector(aStatusVector, u"isc_service_query", *this);
681 }
682
683 detachServiceManager(aServiceHandle);
684}
685
686
687void SAL_CALL Connection::rollback()
688{
689 MutexGuard aGuard( m_aMutex );
690 checkDisposed(Connection_BASE::rBHelper.bDisposed);
691
692 ISC_STATUS status_vector[20];
693
695 {
696 isc_rollback_transaction(status_vector, &m_aTransactionHandle);
697 }
698}
699
701{
702 MutexGuard aGuard( m_aMutex );
703
704 // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent)
705 return Connection_BASE::rBHelper.bDisposed;
706}
707
708Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData( )
709{
710 MutexGuard aGuard( m_aMutex );
711 checkDisposed(Connection_BASE::rBHelper.bDisposed);
712
713 // here we have to create the class with biggest interface
714 // The answer is 42 :-)
715 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
716 if(!xMetaData.is())
717 {
718 xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it
719 m_xMetaData = xMetaData;
720 }
721
722 return xMetaData;
723}
724
725void SAL_CALL Connection::setReadOnly(sal_Bool readOnly)
726{
727 MutexGuard aGuard( m_aMutex );
728 checkDisposed(Connection_BASE::rBHelper.bDisposed);
729
730 m_bIsReadOnly = readOnly;
732}
733
735{
736 MutexGuard aGuard( m_aMutex );
737 checkDisposed(Connection_BASE::rBHelper.bDisposed);
738
739 return m_bIsReadOnly;
740}
741
742void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/)
743{
745}
746
747OUString SAL_CALL Connection::getCatalog()
748{
750 return OUString();
751}
752
753void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level )
754{
755 MutexGuard aGuard( m_aMutex );
756 checkDisposed(Connection_BASE::rBHelper.bDisposed);
757
760}
761
763{
764 MutexGuard aGuard( m_aMutex );
765 checkDisposed(Connection_BASE::rBHelper.bDisposed);
766
768}
769
770Reference< XNameAccess > SAL_CALL Connection::getTypeMap()
771{
772 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this );
773 return nullptr;
774}
775
776void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >&)
777{
778 ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this );
779}
780
781//----- XCloseable -----------------------------------------------------------
782void SAL_CALL Connection::close( )
783{
784 // we just dispose us
785 {
786 MutexGuard aGuard( m_aMutex );
787 checkDisposed(Connection_BASE::rBHelper.bDisposed);
788
789 }
790 dispose();
791}
792
793// XWarningsSupplier
795{
796 // when you collected some warnings -> return it
797 return Any();
798}
799
801{
802 // you should clear your collected warnings here
803}
804
805// XDocumentEventListener
806void SAL_CALL Connection::documentEventOccured( const DocumentEvent& Event )
807{
808 MutexGuard aGuard(m_aMutex);
809
810 if (!m_bIsEmbedded)
811 return;
812
813 if (Event.EventName != "OnSave" && Event.EventName != "OnSaveAs")
814 return;
815
816 commit(); // Commit and close transaction
817 if ( !(m_bIsEmbedded && m_xEmbeddedStorage.is()) )
818 return;
819
821}
822// XEventListener
823void SAL_CALL Connection::disposing(const EventObject& /*rSource*/)
824{
825 MutexGuard aGuard( m_aMutex );
826
827 m_xEmbeddedStorage.clear();
828}
829
831{
832 MutexGuard aGuard( m_aMutex );
833
834 Reference< XResultSet> xRs = getMetaData ()->getTypeInfo ();
835 Reference< XRow> xRow(xRs,UNO_QUERY);
836 // Information for a single SQL type
837
838 // Loop on the result set until we reach end of file
839
840 while (xRs->next ())
841 {
842 OTypeInfo aInfo;
843 aInfo.aTypeName = xRow->getString (1);
844 aInfo.nType = xRow->getShort (2);
845 aInfo.nPrecision = xRow->getInt (3);
846 // aLiteralPrefix = xRow->getString (4);
847 // aLiteralSuffix = xRow->getString (5);
848 // aCreateParams = xRow->getString (6);
849 // bNullable = xRow->getBoolean (7);
850 // bCaseSensitive = xRow->getBoolean (8);
851 // nSearchType = xRow->getShort (9);
852 // bUnsigned = xRow->getBoolean (10);
853 // bCurrency = xRow->getBoolean (11);
854 // bAutoIncrement = xRow->getBoolean (12);
855 aInfo.aLocalTypeName = xRow->getString (13);
856 // nMinimumScale = xRow->getShort (14);
857 aInfo.nMaximumScale = xRow->getShort (15);
858 // nNumPrecRadix = (sal_Int16)xRow->getInt(18);
859
860
861 // Now that we have the type info, save it
862 // in the Hashtable if we don't already have an
863 // entry for this SQL type.
864
865 m_aTypeInfo.push_back(aInfo);
866 }
867
868 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
869 "Type info built.");
870
871 // Close the result set/statement.
872
873 Reference< XCloseable> xClose(xRs,UNO_QUERY);
874 xClose->close();
875
876 SAL_INFO("connectivity.firebird", "buildTypeInfo(). "
877 "Closed.");
878}
879
881{
882 MutexGuard aGuard(m_aMutex);
883
885
886 m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>();
887
888 ISC_STATUS_ARRAY status; /* status vector */
890 {
891 // TODO: confirm whether we need to ask the user here.
892 isc_rollback_transaction(status, &m_aTransactionHandle);
893 }
894
895 if (m_aDBHandle)
896 {
897 if (isc_detach_database(status, &m_aDBHandle))
898 {
899 evaluateStatusVector(status, u"isc_detach_database", *this);
900 }
901 }
902
904
905 cppu::WeakComponentImplHelperBase::disposing();
906
907 m_pDatabaseFileDir.reset();
908}
909
911{
912 MutexGuard aGuard(m_aMutex);
913
915 {
916 SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
917 try
918 {
919 runBackupService(isc_action_svc_backup);
920 }
921 catch (const SQLException& e)
922 {
924 throw WrappedTargetRuntimeException(e.Message, e.Context, a);
925 }
926
927 Reference<XStream> xDBStream(
928 m_xEmbeddedStorage->openStreamElement(our_sFBKLocation, ElementModes::WRITE));
929
930 using namespace ::comphelper;
931 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
932 Reference<XInputStream> xInputStream;
933 if (!xContext.is())
934 return;
935
936 xInputStream = OStorageHelper::GetInputStreamFromURL(m_sFBKPath, xContext);
937 if (xInputStream.is())
938 OStorageHelper::CopyInputToOutput(xInputStream, xDBStream->getOutputStream());
939
940 // remove old fdb and fbk files if exist
941 uno::Reference<ucb::XSimpleFileAccess> xFileAccess
942 = ucb::SimpleFileAccess::create(xContext);
943 if (xFileAccess->exists(m_sFirebirdURL))
944 xFileAccess->kill(m_sFirebirdURL);
945
946 if (xFileAccess->exists(m_sFBKPath))
947 xFileAccess->kill(m_sFBKPath);
948
949 cppu::WeakComponentImplHelperBase::disposing();
950
951 m_pDatabaseFileDir.reset();
952 }
953}
954
956{
957 MutexGuard aGuard(m_aMutex);
958 for (auto const& statement : m_aStatements)
959 {
960 Reference< XComponent > xComp(statement.get(), UNO_QUERY);
961 if (xComp.is())
962 xComp->dispose();
963 }
964 m_aStatements.clear();
965}
966
967uno::Reference< XTablesSupplier > Connection::createCatalog()
968{
969 MutexGuard aGuard(m_aMutex);
970
971 // m_xCatalog is a weak reference. Reuse it if it still exists.
972 Reference< XTablesSupplier > xCatalog = m_xCatalog;
973 if (xCatalog.is())
974 {
975 return xCatalog;
976 }
977 else
978 {
979 xCatalog = new Catalog(this);
980 m_xCatalog = xCatalog;
981 return m_xCatalog;
982 }
983
984}
985
986/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
constexpr OUStringLiteral our_sFBKLocation(u"firebird.fbk")
Older version of LO may store the database in a .fdb file.
IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection", "com.sun.star.sdbc.Connection") Reference< XBlob > Connection
Definition: Connection.cxx:344
constexpr OUStringLiteral our_sFDBLocation(u"firebird.fdb")
Location within the .odb that an embedded .fdb will be stored.
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
static css::uno::Reference< css::io::XInputStream > GetInputStreamFromURL(const OUString &aURL, const css::uno::Reference< css::uno::XComponentContext > &context)
const css::uno::Sequence< sal_Int8 > & getSeq() const
helper class for accessing resources shared by different libraries in the connectivity module
OUString getResourceString(TranslateId pResId) const
loads a string from the shared resource file
virtual void SAL_CALL setReadOnly(sal_Bool readOnly) override
Definition: Connection.cxx:725
void storeDatabase()
Backup and store embedded extracted database to the .odb file.
Definition: Connection.cxx:910
css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog()
Create and/or connect to the sdbcx Catalog.
Definition: Connection.cxx:967
virtual css::uno::Any SAL_CALL getWarnings() override
Definition: Connection.cxx:794
css::uno::WeakReference< css::sdbc::XDatabaseMetaData > m_xMetaData
virtual sal_Bool SAL_CALL getAutoCommit() override
Definition: Connection.cxx:455
virtual sal_Bool SAL_CALL isReadOnly() override
Definition: Connection.cxx:734
virtual void SAL_CALL disposing() override
Definition: Connection.cxx:880
virtual void SAL_CALL setTypeMap(const css::uno::Reference< css::container::XNameAccess > &typeMap) override
void setupTransaction()
Creates a new transaction with the desired parameters, if necessary discarding an existing transactio...
Definition: Connection.cxx:463
css::uno::Reference< css::sdbc::XClob > createClob(ISC_QUAD const *pBlobID)
Definition: Connection.cxx:360
void loadDatabaseFile(const OUString &pSrcLocation, const OUString &pTmpLocation)
Definition: Connection.cxx:547
css::uno::WeakReference< css::sdbcx::XTablesSupplier > m_xCatalog
virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement(const OUString &sql) override
Definition: Connection.cxx:404
virtual sal_Int32 SAL_CALL getTransactionIsolation() override
Definition: Connection.cxx:762
virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap() override
Definition: Connection.cxx:770
bool m_bIsFile
We are using an external (local) file.
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &rId) override
Definition: Connection.cxx:375
virtual void SAL_CALL setTransactionIsolation(sal_Int32 level) override
Definition: Connection.cxx:753
virtual void SAL_CALL documentEventOccured(const css::document::DocumentEvent &Event) override
Definition: Connection.cxx:806
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: Connection.cxx:381
virtual void SAL_CALL clearWarnings() override
Definition: Connection.cxx:800
OWeakRefArray m_aStatements
Statements owned by this connection.
virtual void SAL_CALL setCatalog(const OUString &catalog) override
Definition: Connection.cxx:742
virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData() override
Definition: Connection.cxx:708
virtual sal_Bool SAL_CALL isClosed() override
Definition: Connection.cxx:700
void runBackupService(const short nAction)
Run the backup service, use nAction = isc_action_svc_backup to backup, nAction = isc_action_svc_resto...
Definition: Connection.cxx:614
virtual OUString SAL_CALL getCatalog() override
Definition: Connection.cxx:747
bool m_bIsEmbedded
Denotes that we have a database stored within a .odb file.
void detachServiceManager(isc_svc_handle pServiceHandle)
Definition: Connection.cxx:602
OUString m_sFBKPath
Path for our extracted .fbk file.
virtual void SAL_CALL setAutoCommit(sal_Bool autoCommit) override
Definition: Connection.cxx:442
void construct(const OUString &url, const css::uno::Sequence< css::beans::PropertyValue > &info)
Definition: Connection.cxx:124
virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall(const OUString &sql) override
Definition: Connection.cxx:421
virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement() override
Definition: Connection.cxx:388
std::unique_ptr< ::utl::TempFileNamed > m_pDatabaseFileDir
The temporary folder where we extract the .fbk from a .odb, and also store the temporary ....
virtual void SAL_CALL close() override
Definition: Connection.cxx:782
virtual void SAL_CALL rollback() override
Definition: Connection.cxx:687
css::uno::Reference< css::embed::XStorage > m_xEmbeddedStorage
Handle for the folder within the .odb where we store our .fbk (Only used if m_bIsEmbedded is true).
OUString m_sConnectionURL
The URL passed to us when opening, i.e.
virtual OUString SAL_CALL nativeSQL(const OUString &sql) override
Definition: Connection.cxx:436
virtual void SAL_CALL commit() override
Definition: Connection.cxx:530
OUString m_sFirebirdURL
The URL passed to firebird, i.e.
css::uno::Reference< css::util::XModifiable > m_xParentDocument
Handle for the parent DatabaseDocument.
Any value
ULONG m_refCount
float u
std::mutex m_aMutex
uno_Any a
#define SAL_INFO(area, stream)
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
@ Exception
sal_Int64 getSomethingImpl(const css::uno::Sequence< sal_Int8 > &rId, T *pThis, FallbackToGetSomethingOf< Base >={})
Reference< XComponentContext > getProcessComponentContext()
void checkDisposed(bool _bThrow)
Definition: Driver.cxx:208
void evaluateStatusVector(const ISC_STATUS_ARRAY &rStatusVector, std::u16string_view aCause, const css::uno::Reference< css::uno::XInterface > &_rxContext)
Evaluate a firebird status vector and throw exceptions as necessary.
::cppu::WeakComponentImplHelper< css::document::XDocumentEventListener, css::lang::XServiceInfo, css::lang::XUnoTunnel, css::sdbc::XConnection, css::sdbc::XWarningsSupplier > Connection_BASE
Any SAL_CALL getCaughtException()
void throwFeatureNotImplementedSQLException(const OUString &_rFeatureName, const Reference< XInterface > &_rxContext, const Any &_rNextException)
void throwFunctionNotSupportedSQLException(const OUString &_rFunctionName, const css::uno::Reference< css::uno::XInterface > &_rxContext)
throws an exception with SQL state IM001, saying that a certain function is not supported
void throwGenericSQLException(const OUString &_rMsg, const css::uno::Reference< css::uno::XInterface > &_rxSource)
throw a generic SQLException, i.e.
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
void dispose()
OUString sMessage
unsigned char sal_Bool