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