X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/ibpp/blob.cpp diff --git a/libs/ibpp/blob.cpp b/libs/ibpp/blob.cpp new file mode 100644 index 00000000..298fe706 --- /dev/null +++ b/libs/ibpp/blob.cpp @@ -0,0 +1,381 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// File : $Id: blob.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $ +// Subject : IBPP, Blob class implementation +// +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org) +// +// The contents of this file are subject to the IBPP License (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at http://www.ibpp.org or in the 'license.txt' +// file which must have been distributed along with this file. +// +// This software, distributed under the License, is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +/////////////////////////////////////////////////////////////////////////////// +// +// COMMENTS +// * Tabulations should be set every four characters when editing this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning(disable: 4786 4996) +#ifndef _DEBUG +#pragma warning(disable: 4702) +#endif +#endif + +#include "_ibpp.h" + +#ifdef HAS_HDRSTOP +#pragma hdrstop +#endif + +#include + +using namespace ibpp_internals; + +// (((((((( OBJECT INTERFACE IMPLEMENTATION )))))))) + +void BlobImpl::Open() +{ + if (mHandle != 0) + throw LogicExceptionImpl("Blob::Open", _("Blob already opened.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Blob::Open", _("No Database is attached.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Blob::Open", _("No Transaction is attached.")); + if (! mIdAssigned) + throw LogicExceptionImpl("Blob::Open", _("Blob Id is not assigned.")); + + IBS status; + (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(), + mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Open", _("isc_open_blob2 failed.")); + mWriteMode = false; +} + +void BlobImpl::Create() +{ + if (mHandle != 0) + throw LogicExceptionImpl("Blob::Create", _("Blob already opened.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Blob::Create", _("No Database is attached.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Blob::Create", _("No Transaction is attached.")); + + IBS status; + (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(), + mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Create", + _("isc_create_blob failed.")); + mIdAssigned = true; + mWriteMode = true; +} + +void BlobImpl::Close() +{ + if (mHandle == 0) return; // Not opened anyway + + IBS status; + (*gds.Call()->m_close_blob)(status.Self(), &mHandle); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Close", _("isc_close_blob failed.")); + mHandle = 0; +} + +void BlobImpl::Cancel() +{ + if (mHandle == 0) return; // Not opened anyway + + if (! mWriteMode) + throw LogicExceptionImpl("Blob::Cancel", _("Can't cancel a Blob opened for read")); + + IBS status; + (*gds.Call()->m_cancel_blob)(status.Self(), &mHandle); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Cancel", _("isc_cancel_blob failed.")); + mHandle = 0; + mIdAssigned = false; +} + +int BlobImpl::Read(void* buffer, int size) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Blob::Read", _("The Blob is not opened")); + if (mWriteMode) + throw LogicExceptionImpl("Blob::Read", _("Can't read from Blob opened for write")); + if (size < 1 || size > (64*1024-1)) + throw LogicExceptionImpl("Blob::Read", _("Invalid segment size (max 64Kb-1)")); + + IBS status; + unsigned short bytesread; + ISC_STATUS result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle, &bytesread, + (unsigned short)size, (char*)buffer); + if (result == isc_segstr_eof) return 0; // Fin du blob + if (result != isc_segment && status.Errors()) + throw SQLExceptionImpl(status, "Blob::Read", _("isc_get_segment failed.")); + return (int)bytesread; +} + +void BlobImpl::Write(const void* buffer, int size) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Blob::Write", _("The Blob is not opened")); + if (! mWriteMode) + throw LogicExceptionImpl("Blob::Write", _("Can't write to Blob opened for read")); + if (size < 1 || size > (64*1024-1)) + throw LogicExceptionImpl("Blob::Write", _("Invalid segment size (max 64Kb-1)")); + + IBS status; + (*gds.Call()->m_put_segment)(status.Self(), &mHandle, + (unsigned short)size, (char*)buffer); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Write", _("isc_put_segment failed.")); +} + +void BlobImpl::Info(int* Size, int* Largest, int* Segments) +{ + char items[] = {isc_info_blob_total_length, + isc_info_blob_max_segment, + isc_info_blob_num_segments}; + + if (mHandle == 0) + throw LogicExceptionImpl("Blob::GetInfo", _("The Blob is not opened")); + + IBS status; + RB result(100); + (*gds.Call()->m_blob_info)(status.Self(), &mHandle, sizeof(items), items, + (short)result.Size(), result.Self()); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::GetInfo", _("isc_blob_info failed.")); + + if (Size != 0) *Size = result.GetValue(isc_info_blob_total_length); + if (Largest != 0) *Largest = result.GetValue(isc_info_blob_max_segment); + if (Segments != 0) *Segments = result.GetValue(isc_info_blob_num_segments); +} + +void BlobImpl::Save(const std::string& data) +{ + if (mHandle != 0) + throw LogicExceptionImpl("Blob::Save", _("Blob already opened.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Blob::Save", _("No Database is attached.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Blob::Save", _("No Transaction is attached.")); + + IBS status; + (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(), + mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Save", + _("isc_create_blob failed.")); + mIdAssigned = true; + mWriteMode = true; + + size_t pos = 0; + size_t len = data.size(); + while (len != 0) + { + size_t blklen = (len < 32*1024-1) ? len : 32*1024-1; + status.Reset(); + (*gds.Call()->m_put_segment)(status.Self(), &mHandle, + (unsigned short)blklen, const_cast(data.data()+pos)); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Save", + _("isc_put_segment failed.")); + pos += blklen; + len -= blklen; + } + + status.Reset(); + (*gds.Call()->m_close_blob)(status.Self(), &mHandle); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Save", _("isc_close_blob failed.")); + mHandle = 0; +} + +void BlobImpl::Load(std::string& data) +{ + if (mHandle != 0) + throw LogicExceptionImpl("Blob::Load", _("Blob already opened.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Blob::Load", _("No Database is attached.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Blob::Load", _("No Transaction is attached.")); + if (! mIdAssigned) + throw LogicExceptionImpl("Blob::Load", _("Blob Id is not assigned.")); + + IBS status; + (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(), + mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Load", _("isc_open_blob2 failed.")); + mWriteMode = false; + + size_t blklen = 32*1024-1; + data.resize(blklen); + + size_t size = 0; + size_t pos = 0; + for (;;) + { + status.Reset(); + unsigned short bytesread; + ISC_STATUS result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle, + &bytesread, (unsigned short)blklen, + const_cast(data.data()+pos)); + if (result == isc_segstr_eof) break; // End of blob + if (result != isc_segment && status.Errors()) + throw SQLExceptionImpl(status, "Blob::Load", _("isc_get_segment failed.")); + + pos += bytesread; + size += bytesread; + data.resize(size + blklen); + } + data.resize(size); + + status.Reset(); + (*gds.Call()->m_close_blob)(status.Self(), &mHandle); + if (status.Errors()) + throw SQLExceptionImpl(status, "Blob::Load", _("isc_close_blob failed.")); + mHandle = 0; +} + +IBPP::Database BlobImpl::DatabasePtr() const +{ + if (mDatabase == 0) throw LogicExceptionImpl("Blob::DatabasePtr", + _("No Database is attached.")); + return mDatabase; +} + +IBPP::Transaction BlobImpl::TransactionPtr() const +{ + if (mTransaction == 0) throw LogicExceptionImpl("Blob::TransactionPtr", + _("No Transaction is attached.")); + return mTransaction; +} + +IBPP::IBlob* BlobImpl::AddRef() +{ + ASSERTION(mRefCount >= 0); + ++mRefCount; + return this; +} + +void BlobImpl::Release() +{ + // Release cannot throw, except in DEBUG builds on assertion + ASSERTION(mRefCount >= 0); + --mRefCount; + try { if (mRefCount <= 0) delete this; } + catch (...) { } +} + +// (((((((( OBJECT INTERNAL METHODS )))))))) + +void BlobImpl::Init() +{ + mIdAssigned = false; + mWriteMode = false; + mHandle = 0; + mDatabase = 0; + mTransaction = 0; +} + +void BlobImpl::SetId(ISC_QUAD* quad) +{ + if (mHandle != 0) + throw LogicExceptionImpl("BlobImpl::SetId", _("Can't set Id on an opened BlobImpl.")); + if (quad == 0) + throw LogicExceptionImpl("BlobImpl::SetId", _("Null Id reference detected.")); + + memcpy(&mId, quad, sizeof(mId)); + mIdAssigned = true; +} + +void BlobImpl::GetId(ISC_QUAD* quad) +{ + if (mHandle != 0) + throw LogicExceptionImpl("BlobImpl::GetId", _("Can't get Id on an opened BlobImpl.")); + if (! mWriteMode) + throw LogicExceptionImpl("BlobImpl::GetId", _("Can only get Id of a newly created Blob.")); + if (quad == 0) + throw LogicExceptionImpl("BlobImpl::GetId", _("Null Id reference detected.")); + + memcpy(quad, &mId, sizeof(mId)); +} + +void BlobImpl::AttachDatabaseImpl(DatabaseImpl* database) +{ + if (database == 0) throw LogicExceptionImpl("Blob::AttachDatabase", + _("Can't attach a NULL Database object.")); + + if (mDatabase != 0) mDatabase->DetachBlobImpl(this); + mDatabase = database; + mDatabase->AttachBlobImpl(this); +} + +void BlobImpl::AttachTransactionImpl(TransactionImpl* transaction) +{ + if (transaction == 0) throw LogicExceptionImpl("Blob::AttachTransaction", + _("Can't attach a NULL Transaction object.")); + + if (mTransaction != 0) mTransaction->DetachBlobImpl(this); + mTransaction = transaction; + mTransaction->AttachBlobImpl(this); +} + +void BlobImpl::DetachDatabaseImpl() +{ + if (mDatabase == 0) return; + + mDatabase->DetachBlobImpl(this); + mDatabase = 0; +} + +void BlobImpl::DetachTransactionImpl() +{ + if (mTransaction == 0) return; + + mTransaction->DetachBlobImpl(this); + mTransaction = 0; +} + +BlobImpl::BlobImpl(DatabaseImpl* database, TransactionImpl* transaction) + : mRefCount(0) +{ + Init(); + AttachDatabaseImpl(database); + if (transaction != 0) AttachTransactionImpl(transaction); +} + +BlobImpl::~BlobImpl() +{ + try + { + if (mHandle != 0) + { + if (mWriteMode) Cancel(); + else Close(); + } + } + catch (...) { } + + try { if (mTransaction != 0) mTransaction->DetachBlobImpl(this); } + catch (...) { } + try { if (mDatabase != 0) mDatabase->DetachBlobImpl(this); } + catch (...) { } +} + +// +// EOF +//