]> git.stg.codes - stg.git/blob - libs/ibpp/blob.cpp
More subscriptions, less notifiers.
[stg.git] / libs / ibpp / blob.cpp
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //\r
3 //      File    : $Id: blob.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
4 //      Subject : IBPP, Blob class implementation\r
5 //\r
6 ///////////////////////////////////////////////////////////////////////////////\r
7 //\r
8 //      (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
9 //\r
10 //      The contents of this file are subject to the IBPP License (the "License");\r
11 //      you may not use this file except in compliance with the License.  You may\r
12 //      obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
13 //      file which must have been distributed along with this file.\r
14 //\r
15 //      This software, distributed under the License, is distributed on an "AS IS"\r
16 //      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
17 //      License for the specific language governing rights and limitations\r
18 //      under the License.\r
19 //\r
20 ///////////////////////////////////////////////////////////////////////////////\r
21 //\r
22 //      COMMENTS\r
23 //      * Tabulations should be set every four characters when editing this file.\r
24 //\r
25 ///////////////////////////////////////////////////////////////////////////////\r
26 \r
27 #ifdef _MSC_VER\r
28 #pragma warning(disable: 4786 4996)\r
29 #ifndef _DEBUG\r
30 #pragma warning(disable: 4702)\r
31 #endif\r
32 #endif\r
33 \r
34 #include "_ibpp.h"\r
35 \r
36 #ifdef HAS_HDRSTOP\r
37 #pragma hdrstop\r
38 #endif\r
39 \r
40 #include <cstring>\r
41 \r
42 using namespace ibpp_internals;\r
43 \r
44 //      (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
45 \r
46 void BlobImpl::Open()\r
47 {\r
48         if (mHandle != 0)\r
49                 throw LogicExceptionImpl("Blob::Open", _("Blob already opened."));\r
50         if (mDatabase == 0)\r
51                 throw LogicExceptionImpl("Blob::Open", _("No Database is attached."));\r
52         if (mTransaction == 0)\r
53                 throw LogicExceptionImpl("Blob::Open", _("No Transaction is attached."));\r
54         if (! mIdAssigned)\r
55                 throw LogicExceptionImpl("Blob::Open", _("Blob Id is not assigned."));\r
56 \r
57         IBS status;\r
58         (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
59                 mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
60         if (status.Errors())\r
61                 throw SQLExceptionImpl(status, "Blob::Open", _("isc_open_blob2 failed."));\r
62         mWriteMode = false;\r
63 }\r
64 \r
65 void BlobImpl::Create()\r
66 {\r
67         if (mHandle != 0)\r
68                 throw LogicExceptionImpl("Blob::Create", _("Blob already opened."));\r
69         if (mDatabase == 0)\r
70                 throw LogicExceptionImpl("Blob::Create", _("No Database is attached."));\r
71         if (mTransaction == 0)\r
72                 throw LogicExceptionImpl("Blob::Create", _("No Transaction is attached."));\r
73 \r
74         IBS status;\r
75         (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
76                 mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
77         if (status.Errors())\r
78                 throw SQLExceptionImpl(status, "Blob::Create",\r
79                         _("isc_create_blob failed."));\r
80         mIdAssigned = true;\r
81         mWriteMode = true;\r
82 }\r
83 \r
84 void BlobImpl::Close()\r
85 {\r
86         if (mHandle == 0) return;       // Not opened anyway\r
87 \r
88         IBS status;\r
89         (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
90         if (status.Errors())\r
91                 throw SQLExceptionImpl(status, "Blob::Close", _("isc_close_blob failed."));\r
92         mHandle = 0;\r
93 }\r
94 \r
95 void BlobImpl::Cancel()\r
96 {\r
97         if (mHandle == 0) return;       // Not opened anyway\r
98 \r
99         if (! mWriteMode)\r
100                 throw LogicExceptionImpl("Blob::Cancel", _("Can't cancel a Blob opened for read"));\r
101 \r
102         IBS status;\r
103         (*gds.Call()->m_cancel_blob)(status.Self(), &mHandle);\r
104         if (status.Errors())\r
105                 throw SQLExceptionImpl(status, "Blob::Cancel", _("isc_cancel_blob failed."));\r
106         mHandle = 0;\r
107         mIdAssigned = false;\r
108 }\r
109 \r
110 int BlobImpl::Read(void* buffer, int size)\r
111 {\r
112         if (mHandle == 0)\r
113                 throw LogicExceptionImpl("Blob::Read", _("The Blob is not opened"));\r
114         if (mWriteMode)\r
115                 throw LogicExceptionImpl("Blob::Read", _("Can't read from Blob opened for write"));\r
116         if (size < 1 || size > (64*1024-1))\r
117                 throw LogicExceptionImpl("Blob::Read", _("Invalid segment size (max 64Kb-1)"));\r
118 \r
119         IBS status;\r
120         unsigned short bytesread;\r
121         ISC_STATUS result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle, &bytesread,\r
122                                         (unsigned short)size, (char*)buffer);\r
123         if (result == isc_segstr_eof) return 0; // Fin du blob\r
124         if (result != isc_segment && status.Errors())\r
125                 throw SQLExceptionImpl(status, "Blob::Read", _("isc_get_segment failed."));\r
126         return (int)bytesread;\r
127 }\r
128 \r
129 void BlobImpl::Write(const void* buffer, int size)\r
130 {\r
131         if (mHandle == 0)\r
132                 throw LogicExceptionImpl("Blob::Write", _("The Blob is not opened"));\r
133         if (! mWriteMode)\r
134                 throw LogicExceptionImpl("Blob::Write", _("Can't write to Blob opened for read"));\r
135         if (size < 1 || size > (64*1024-1))\r
136                 throw LogicExceptionImpl("Blob::Write", _("Invalid segment size (max 64Kb-1)"));\r
137 \r
138         IBS status;\r
139         (*gds.Call()->m_put_segment)(status.Self(), &mHandle,\r
140                 (unsigned short)size, (char*)buffer);\r
141         if (status.Errors())\r
142                 throw SQLExceptionImpl(status, "Blob::Write", _("isc_put_segment failed."));\r
143 }\r
144 \r
145 void BlobImpl::Info(int* Size, int* Largest, int* Segments)\r
146 {\r
147         char items[] = {isc_info_blob_total_length,\r
148                                         isc_info_blob_max_segment,\r
149                                         isc_info_blob_num_segments};\r
150 \r
151         if (mHandle == 0)\r
152                 throw LogicExceptionImpl("Blob::GetInfo", _("The Blob is not opened"));\r
153 \r
154         IBS status;\r
155         RB result(100);\r
156         (*gds.Call()->m_blob_info)(status.Self(), &mHandle, sizeof(items), items,\r
157                 (short)result.Size(), result.Self());\r
158         if (status.Errors())\r
159                 throw SQLExceptionImpl(status, "Blob::GetInfo", _("isc_blob_info failed."));\r
160 \r
161         if (Size != 0) *Size = result.GetValue(isc_info_blob_total_length);\r
162         if (Largest != 0) *Largest = result.GetValue(isc_info_blob_max_segment);\r
163         if (Segments != 0) *Segments = result.GetValue(isc_info_blob_num_segments);\r
164 }\r
165 \r
166 void BlobImpl::Save(const std::string& data)\r
167 {\r
168         if (mHandle != 0)\r
169                 throw LogicExceptionImpl("Blob::Save", _("Blob already opened."));\r
170         if (mDatabase == 0)\r
171                 throw LogicExceptionImpl("Blob::Save", _("No Database is attached."));\r
172         if (mTransaction == 0)\r
173                 throw LogicExceptionImpl("Blob::Save", _("No Transaction is attached."));\r
174 \r
175         IBS status;\r
176         (*gds.Call()->m_create_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
177                 mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
178         if (status.Errors())\r
179                 throw SQLExceptionImpl(status, "Blob::Save",\r
180                         _("isc_create_blob failed."));\r
181         mIdAssigned = true;\r
182         mWriteMode = true;\r
183 \r
184         size_t pos = 0;\r
185         size_t len = data.size();\r
186         while (len != 0)\r
187         {\r
188                 size_t blklen = (len < 32*1024-1) ? len : 32*1024-1;\r
189                 status.Reset();\r
190                 (*gds.Call()->m_put_segment)(status.Self(), &mHandle,\r
191                         (unsigned short)blklen, const_cast<char*>(data.data()+pos));\r
192                 if (status.Errors())\r
193                         throw SQLExceptionImpl(status, "Blob::Save",\r
194                                         _("isc_put_segment failed."));\r
195                 pos += blklen;\r
196                 len -= blklen;\r
197         }\r
198         \r
199         status.Reset();\r
200         (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
201         if (status.Errors())\r
202                 throw SQLExceptionImpl(status, "Blob::Save", _("isc_close_blob failed."));\r
203         mHandle = 0;\r
204 }\r
205 \r
206 void BlobImpl::Load(std::string& data)\r
207 {\r
208         if (mHandle != 0)\r
209                 throw LogicExceptionImpl("Blob::Load", _("Blob already opened."));\r
210         if (mDatabase == 0)\r
211                 throw LogicExceptionImpl("Blob::Load", _("No Database is attached."));\r
212         if (mTransaction == 0)\r
213                 throw LogicExceptionImpl("Blob::Load", _("No Transaction is attached."));\r
214         if (! mIdAssigned)\r
215                 throw LogicExceptionImpl("Blob::Load", _("Blob Id is not assigned."));\r
216 \r
217         IBS status;\r
218         (*gds.Call()->m_open_blob2)(status.Self(), mDatabase->GetHandlePtr(),\r
219                 mTransaction->GetHandlePtr(), &mHandle, &mId, 0, 0);\r
220         if (status.Errors())\r
221                 throw SQLExceptionImpl(status, "Blob::Load", _("isc_open_blob2 failed."));\r
222         mWriteMode = false;\r
223 \r
224         size_t blklen = 32*1024-1;\r
225         data.resize(blklen);\r
226 \r
227         size_t size = 0;\r
228         size_t pos = 0;\r
229         for (;;)\r
230         {\r
231                 status.Reset();\r
232                 unsigned short bytesread;\r
233                 ISC_STATUS result = (*gds.Call()->m_get_segment)(status.Self(), &mHandle,\r
234                                                 &bytesread, (unsigned short)blklen,\r
235                                                         const_cast<char*>(data.data()+pos));\r
236                 if (result == isc_segstr_eof) break;    // End of blob\r
237                 if (result != isc_segment && status.Errors())\r
238                         throw SQLExceptionImpl(status, "Blob::Load", _("isc_get_segment failed."));\r
239 \r
240                 pos += bytesread;\r
241                 size += bytesread;\r
242                 data.resize(size + blklen);\r
243         }\r
244         data.resize(size);\r
245         \r
246         status.Reset();\r
247         (*gds.Call()->m_close_blob)(status.Self(), &mHandle);\r
248         if (status.Errors())\r
249                 throw SQLExceptionImpl(status, "Blob::Load", _("isc_close_blob failed."));\r
250         mHandle = 0;\r
251 }\r
252 \r
253 IBPP::Database BlobImpl::DatabasePtr() const\r
254 {\r
255         if (mDatabase == 0) throw LogicExceptionImpl("Blob::DatabasePtr",\r
256                         _("No Database is attached."));\r
257         return mDatabase;\r
258 }\r
259 \r
260 IBPP::Transaction BlobImpl::TransactionPtr() const\r
261 {\r
262         if (mTransaction == 0) throw LogicExceptionImpl("Blob::TransactionPtr",\r
263                         _("No Transaction is attached."));\r
264         return mTransaction;\r
265 }\r
266 \r
267 IBPP::IBlob* BlobImpl::AddRef()\r
268 {\r
269         ASSERTION(mRefCount >= 0);\r
270         ++mRefCount;\r
271         return this;\r
272 }\r
273 \r
274 void BlobImpl::Release()\r
275 {\r
276         // Release cannot throw, except in DEBUG builds on assertion\r
277         ASSERTION(mRefCount >= 0);\r
278         --mRefCount;\r
279         try { if (mRefCount <= 0) delete this; }\r
280                 catch (...) { }\r
281 }\r
282 \r
283 //      (((((((( OBJECT INTERNAL METHODS ))))))))\r
284 \r
285 void BlobImpl::Init()\r
286 {\r
287         mIdAssigned = false;\r
288         mWriteMode = false;\r
289         mHandle = 0;\r
290         mDatabase = 0;\r
291         mTransaction = 0;\r
292 }\r
293 \r
294 void BlobImpl::SetId(ISC_QUAD* quad)\r
295 {\r
296         if (mHandle != 0)\r
297                 throw LogicExceptionImpl("BlobImpl::SetId", _("Can't set Id on an opened BlobImpl."));\r
298         if (quad == 0)\r
299                 throw LogicExceptionImpl("BlobImpl::SetId", _("Null Id reference detected."));\r
300 \r
301         memcpy(&mId, quad, sizeof(mId));\r
302         mIdAssigned = true;\r
303 }\r
304 \r
305 void BlobImpl::GetId(ISC_QUAD* quad)\r
306 {\r
307         if (mHandle != 0)\r
308                 throw LogicExceptionImpl("BlobImpl::GetId", _("Can't get Id on an opened BlobImpl."));\r
309         if (! mWriteMode)\r
310                 throw LogicExceptionImpl("BlobImpl::GetId", _("Can only get Id of a newly created Blob."));\r
311         if (quad == 0)\r
312                 throw LogicExceptionImpl("BlobImpl::GetId", _("Null Id reference detected."));\r
313 \r
314         memcpy(quad, &mId, sizeof(mId));\r
315 }\r
316 \r
317 void BlobImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
318 {\r
319         if (database == 0) throw LogicExceptionImpl("Blob::AttachDatabase",\r
320                         _("Can't attach a NULL Database object."));\r
321 \r
322         if (mDatabase != 0) mDatabase->DetachBlobImpl(this);\r
323         mDatabase = database;\r
324         mDatabase->AttachBlobImpl(this);\r
325 }\r
326 \r
327 void BlobImpl::AttachTransactionImpl(TransactionImpl* transaction)\r
328 {\r
329         if (transaction == 0) throw LogicExceptionImpl("Blob::AttachTransaction",\r
330                         _("Can't attach a NULL Transaction object."));\r
331 \r
332         if (mTransaction != 0) mTransaction->DetachBlobImpl(this);\r
333         mTransaction = transaction;\r
334         mTransaction->AttachBlobImpl(this);\r
335 }\r
336 \r
337 void BlobImpl::DetachDatabaseImpl()\r
338 {\r
339         if (mDatabase == 0) return;\r
340 \r
341         mDatabase->DetachBlobImpl(this);\r
342         mDatabase = 0;\r
343 }\r
344 \r
345 void BlobImpl::DetachTransactionImpl()\r
346 {\r
347         if (mTransaction == 0) return;\r
348 \r
349         mTransaction->DetachBlobImpl(this);\r
350         mTransaction = 0;\r
351 }\r
352 \r
353 BlobImpl::BlobImpl(DatabaseImpl* database, TransactionImpl* transaction)\r
354         : mRefCount(0)\r
355 {\r
356         Init();\r
357         AttachDatabaseImpl(database);\r
358         if (transaction != 0) AttachTransactionImpl(transaction);\r
359 }\r
360 \r
361 BlobImpl::~BlobImpl()\r
362 {\r
363         try\r
364         {\r
365                 if (mHandle != 0)\r
366                 {\r
367                         if (mWriteMode) Cancel();\r
368                         else Close();\r
369                 }\r
370         }\r
371         catch (...) { }\r
372         \r
373         try { if (mTransaction != 0) mTransaction->DetachBlobImpl(this); }\r
374                 catch (...) { }\r
375         try { if (mDatabase != 0) mDatabase->DetachBlobImpl(this); }\r
376                 catch (...) { }\r
377 }\r
378 \r
379 //\r
380 //      EOF\r
381 //\r