]> git.stg.codes - stg.git/blobdiff - libs/ibpp/blob.cpp
Port to CMake, get rid of os_int.h.
[stg.git] / libs / ibpp / blob.cpp
diff --git a/libs/ibpp/blob.cpp b/libs/ibpp/blob.cpp
new file mode 100644 (file)
index 0000000..298fe70
--- /dev/null
@@ -0,0 +1,381 @@
+///////////////////////////////////////////////////////////////////////////////\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