Skip to content

Instantly share code, notes, and snippets.

@mariuz
Created March 24, 2015 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mariuz/60d4d1edfe83c0670648 to your computer and use it in GitHub Desktop.
Save mariuz/60d4d1edfe83c0670648 to your computer and use it in GitHub Desktop.
save_to_fbk.patch
diff --git a/connectivity/source/drivers/firebird/Connection.cxx b/connectivity/source/drivers/firebird/Connection.cxx
index 8958bd2..1f83f94 100644
--- a/connectivity/source/drivers/firebird/Connection.cxx
+++ b/connectivity/source/drivers/firebird/Connection.cxx
@@ -75,7 +75,7 @@ using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::uno;
-const OUString Connection::our_sDBLocation( "firebird.fdb" );
+const OUString Connection::our_sFBKLocation( "firebird.fbk" );
Connection::Connection(FirebirdDriver* _pDriver)
: Connection_BASE(m_aMutex)
@@ -166,23 +166,24 @@ void Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyV
bIsNewDatabase = !m_xEmbeddedStorage->hasElements();
- m_pExtractedFDBFile.reset(new ::utl::TempFile(NULL, true));
- m_sFirebirdURL = m_pExtractedFDBFile->GetFileName() + "/firebird.fdb";
+ m_pDatabaseFileDir.reset(new ::utl::TempFile(NULL, true));
+ m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb";
+ m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk";
SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL);
if (!bIsNewDatabase)
{
- SAL_INFO("connectivity.firebird", "Extracting .fdb from .odb" );
- if (!m_xEmbeddedStorage->isStreamElement(our_sDBLocation))
+ SAL_INFO("connectivity.firebird", "Extracting .fbk from .odb" );
+ if (!m_xEmbeddedStorage->isStreamElement(our_sFBKLocation))
{
::connectivity::SharedResources aResources;
const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION);
::dbtools::throwGenericSQLException(sMessage ,*this);
}
- Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sDBLocation,
- ElementModes::READ));
+ Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation,
+ ElementModes::READ));
uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess(
ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ),
@@ -194,7 +195,7 @@ void Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyV
::dbtools::throwGenericSQLException(sMessage ,*this);
}
- xFileAccess->writeFile(m_sFirebirdURL,xDBStream->getInputStream());
+ xFileAccess->writeFile(m_sFBKPath,xDBStream->getInputStream());
}
// TOOO: Get DB properties from XML
@@ -281,6 +282,10 @@ void Connection::construct(const ::rtl::OUString& url, const Sequence< PropertyV
}
else
{
+ if (m_bIsEmbedded) // We need to restore the .fbk first
+ {
+ runBackupService(isc_action_svc_restore);
+ }
aErr = isc_attach_database(status,
m_sFirebirdURL.getLength(),
OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8).getStr(),
@@ -523,6 +528,128 @@ isc_tr_handle& Connection::getTransaction()
return m_aTransactionHandle;
}
+isc_svc_handle Connection::attachServiceManager()
+{
+ ISC_STATUS_ARRAY aStatusVector;
+ isc_svc_handle aServiceHandle = 0;
+
+ char aSPBBuffer[] = { isc_spb_version, isc_spb_current_version};
+
+ if (isc_service_attach(aStatusVector,
+ 0, // Denotes null-terminated string next
+ "service_mgr",
+ &aServiceHandle,
+ sizeof(aSPBBuffer),
+ aSPBBuffer))
+ {
+ evaluateStatusVector(aStatusVector,
+ "isc_service_attach",
+ *this);
+ }
+
+ return aServiceHandle;
+}
+
+void Connection::detachServiceManager(isc_svc_handle aServiceHandle)
+{
+ ISC_STATUS_ARRAY aStatusVector;
+ if (isc_service_detach(aStatusVector,
+ &aServiceHandle))
+ {
+ evaluateStatusVector(aStatusVector,
+ "isc_service_detach",
+ *this);
+ }
+}
+
+void Connection::runBackupService(const short nAction)
+{
+ assert(nAction == isc_action_svc_backup
+ || nAction == isc_action_svc_restore);
+
+ ISC_STATUS_ARRAY aStatusVector;
+
+ char sRequest[200];
+ char* pRequest = sRequest;
+
+ *pRequest++ = nAction;
+
+ *pRequest++ = isc_spb_dbname; // The .fdb
+ sal_uInt16 nURLLength = m_sFirebirdURL.getLength();
+ *((sal_uInt16*) pRequest) = nURLLength;
+ pRequest += 2;
+ strncpy(pRequest,
+ OUStringToOString(m_sFirebirdURL,
+ RTL_TEXTENCODING_UTF8).getStr(),
+ nURLLength);
+ pRequest += nURLLength;
+
+ *pRequest++ = isc_spb_bkp_file; // The fbk
+ sal_uInt16 nPathLength = m_sFBKPath.getLength();
+ *((sal_uInt16*) pRequest) = nPathLength;
+ pRequest += 2;
+ strncpy(pRequest,
+ OUStringToOString(m_sFBKPath,
+ RTL_TEXTENCODING_UTF8).getStr(),
+ nPathLength);
+ pRequest += nPathLength;
+
+ // TODO: not sure we really need this yet -- assumed by default?
+ if (nAction == isc_action_svc_restore)
+ {
+ *pRequest++ = isc_spb_options;
+ // This is a 4 byte value (the docs suggest unsigned long...)
+ *((sal_uInt32*) pRequest) = isc_spb_res_create;
+ pRequest += 4;
+ }
+
+ *pRequest++ = isc_spb_verbose;
+
+ isc_svc_handle aServiceHandle = attachServiceManager();
+
+ if (isc_service_start(aStatusVector,
+ &aServiceHandle,
+ NULL,
+ pRequest - sRequest,
+ sRequest))
+ {
+ evaluateStatusVector(aStatusVector, "isc_service_start", *this);
+ }
+
+ while (true)
+ {
+ char aInfoSPB = isc_info_svc_line;
+ char aResults[512];
+ char* pResults = aResults;
+ isc_service_query(aStatusVector,
+ &aServiceHandle,
+ 0, // Reserved null
+ 0,0, // "send" spb -- size and spb -- not needed?
+ 1,
+ &aInfoSPB,
+ sizeof(aResults),
+ aResults);
+ if (isc_vax_integer(pResults, 1) == isc_info_svc_line)
+ {
+ if (isc_vax_integer(pResults + 1, 2) == 0) // Empty string == command finished
+ break;
+
+ OUString aData(pResults + 3,
+ isc_vax_integer(pResults, 2),
+ RTL_TEXTENCODING_UTF8);
+ SAL_INFO("connectivity.firebird", "backupService: " << aData);
+ }
+ else if (isc_vax_integer(pResults, 2) == isc_info_truncated)
+ {
+ SAL_INFO("connectivity.firebird", "backupService output truncated");
+ break;
+ }
+
+ }
+
+ detachServiceManager(aServiceHandle);
+}
+
void SAL_CALL Connection::commit() throw(SQLException, RuntimeException, std::exception)
{
MutexGuard aGuard( m_aMutex );
@@ -677,11 +804,15 @@ void SAL_CALL Connection::documentEventOccured( const DocumentEvent& _Event )
commit(); // Commit and close transaction
if ( m_bIsEmbedded && m_xEmbeddedStorage.is() )
{
- SAL_INFO("connectivity.firebird", "Writing .fdb into .odb" );
-
- Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sDBLocation,
- ElementModes::WRITE));
-
+ SAL_INFO("connectivity.firebird", "Writing .fbk from running db");
+ runBackupService(isc_action_svc_backup);
+
+ SAL_INFO("connectivity.firebird", "Writing .fdk into .odb" );
+ Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation,
+ ElementModes::WRITE));
+ // TODO: verify the backup actually exists -- the backup service
+ // can fail without giving any sane error messages / telling us
+ // that it failed.
using namespace ::comphelper;
Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
Reference< XInputStream > xInputStream;
@@ -691,7 +822,6 @@ void SAL_CALL Connection::documentEventOccured( const DocumentEvent& _Event )
if (xInputStream.is())
OStorageHelper::CopyInputToOutput( xInputStream,
xDBStream->getOutputStream());
- // TODO: ensure db is in safe state
}
}
}
@@ -780,10 +910,10 @@ void Connection::disposing()
cppu::WeakComponentImplHelperBase::disposing();
m_xDriver.clear();
- if (m_pExtractedFDBFile)
+ if (m_pDatabaseFileDir)
{
- ::utl::removeTree(m_pExtractedFDBFile->GetURL());
- m_pExtractedFDBFile.reset();
+ ::utl::removeTree(m_pDatabaseFileDir->GetURL());
+ m_pDatabaseFileDir.reset();
}
}
diff --git a/connectivity/source/drivers/firebird/Connection.hxx b/connectivity/source/drivers/firebird/Connection.hxx
index 22dccf1..51370b1 100644
--- a/connectivity/source/drivers/firebird/Connection.hxx
+++ b/connectivity/source/drivers/firebird/Connection.hxx
@@ -74,8 +74,8 @@ namespace connectivity
/**
* Location within the .odb that an embedded .fdb will be stored.
* Only relevant for embedded dbs.
- */
- static const OUString our_sDBLocation;
+ */
+ static const OUString our_sFBKLocation;
protected:
::osl::Mutex m_aMutex;
@@ -115,10 +115,31 @@ namespace connectivity
::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >
m_xEmbeddedStorage;
/**
- * The temporary folder where we extract the .fdb from a .odb.
+ * The temporary folder where we extract the .fbk from a .odb,
+ * and also store the temporary .fdb
* It is only valid if m_bIsEmbedded is true.
+ *
+ * The extracted .fbk is written in firebird.fbk, the temporary
+ * .fdb is stored as firebird.fdb.
+ */
+ ::boost::scoped_ptr< ::utl::TempFile > m_pDatabaseFileDir;
+ /**
+ * Path for our extracted .fbk file.
+ *
+ * (The temporary .fdb is our m_sFirebirdURL.)
*/
- ::boost::scoped_ptr< ::utl::TempFile > m_pExtractedFDBFile;
+ ::rtl::OUString m_sFBKPath;
+
+ /**
+ * Run the backup service, use nAction =
+ * isc_action_svc_backup to backup, nAction = isc_action_svc_restore
+ * to restore.
+ */
+ void runBackupService(const short nAction);
+
+ isc_svc_handle attachServiceManager();
+
+ void detachServiceManager(isc_svc_handle pServiceHandle);
/** We are using an external (local) file */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment