SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

blob.cpp

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski
00003 // Distributed under the Boost Software License, Version 1.0.
00004 // (See accompanying file LICENSE_1_0.txt or copy at
00005 // http://www.boost.org/LICENSE_1_0.txt)
00006 //
00007 
00008 #define SOCI_FIREBIRD_SOURCE
00009 #include "soci-firebird.h"
00010 #include "error-firebird.h"
00011 
00012 using namespace soci;
00013 using namespace soci::details::firebird;
00014 
00015 firebird_blob_backend::firebird_blob_backend(firebird_session_backend &session)
00016         : session_(session), from_db_(false), bhp_(0), loaded_(false),
00017         max_seg_size_(0)
00018 {}
00019 
00020 firebird_blob_backend::~firebird_blob_backend()
00021 {
00022     cleanUp();
00023 }
00024 
00025 std::size_t firebird_blob_backend::get_len()
00026 {
00027     if (from_db_ && bhp_ == 0)
00028     {
00029         open();
00030     }
00031 
00032     return data_.size();
00033 }
00034 
00035 std::size_t firebird_blob_backend::read(
00036     std::size_t offset, char * buf, std::size_t toRead)
00037 {
00038     if (from_db_ && (loaded_ == false))
00039     {
00040         // this is blob fetched from database, but not loaded yet
00041         load();
00042     }
00043 
00044     std::size_t size = data_.size();
00045 
00046     if (offset > size)
00047     {
00048         throw soci_error("Can't read past-the-end of BLOB data");
00049     }
00050 
00051     char * itr = buf;
00052     std::size_t limit = size - offset < toRead ? size - offset : toRead;
00053     std::size_t index = 0;
00054 
00055     while (index < limit)
00056     {
00057         *itr = data_[offset+index];
00058         ++index;
00059         ++itr;
00060     }
00061 
00062     return limit;
00063 }
00064 
00065 std::size_t firebird_blob_backend::write(std::size_t offset, char const * buf,
00066                                        std::size_t toWrite)
00067 {
00068     if (from_db_ && (loaded_ == false))
00069     {
00070         // this is blob fetched from database, but not loaded yet
00071         load();
00072     }
00073 
00074     std::size_t size = data_.size();
00075 
00076     if (offset > size)
00077     {
00078         throw soci_error("Can't write past-the-end of BLOB data");
00079     }
00080 
00081     // make sure there is enough space in buffer
00082     if (toWrite > (size - offset))
00083     {
00084         data_.resize(size + (toWrite - (size - offset)));
00085     }
00086 
00087     writeBuffer(offset, buf, toWrite);
00088 
00089     return toWrite;
00090 }
00091 
00092 std::size_t firebird_blob_backend::append(
00093     char const * buf, std::size_t toWrite)
00094 {
00095     if (from_db_ && (loaded_ == false))
00096     {
00097         // this is blob fetched from database, but not loaded yet
00098         load();
00099     }
00100 
00101     std::size_t size = data_.size();
00102     data_.resize(size + toWrite);
00103 
00104     writeBuffer(size, buf, toWrite);
00105 
00106     return toWrite;
00107 }
00108 
00109 void firebird_blob_backend::trim(std::size_t newLen)
00110 {
00111     if (from_db_ && (loaded_ == false))
00112     {
00113         // this is blob fetched from database, but not loaded yet
00114         load();
00115     }
00116 
00117     data_.resize(newLen);
00118 }
00119 
00120 void firebird_blob_backend::writeBuffer(std::size_t offset,
00121                                       char const * buf, std::size_t toWrite)
00122 {
00123     char const * itr = buf;
00124     char const * end_itr = buf + toWrite;
00125 
00126     while (itr!=end_itr)
00127     {
00128         data_[offset++] = *itr++;
00129     }
00130 }
00131 
00132 void firebird_blob_backend::open()
00133 {
00134     if (bhp_ != 0)
00135     {
00136         // BLOB already opened
00137         return;
00138     }
00139 
00140     ISC_STATUS stat[20];
00141 
00142     if (isc_open_blob2(stat, &session_.dbhp_, &session_.trhp_, &bhp_,
00143                        &bid_, 0, NULL))
00144     {
00145         bhp_ = 0L;
00146         throw_iscerror(stat);
00147     }
00148 
00149     // get basic blob info
00150     long blob_size = getBLOBInfo();
00151 
00152     data_.resize(blob_size);
00153 }
00154 
00155 void firebird_blob_backend::cleanUp()
00156 {
00157     from_db_ = false;
00158     loaded_ = false;
00159     max_seg_size_ = 0;
00160     data_.resize(0);
00161 
00162     if (bhp_ != 0)
00163     {
00164         // close blob
00165         ISC_STATUS stat[20];
00166         if (isc_close_blob(stat, &bhp_))
00167         {
00168             throw_iscerror(stat);
00169         }
00170         bhp_ = 0;
00171     }
00172 }
00173 
00174 // loads blob data into internal buffer
00175 void firebird_blob_backend::load()
00176 {
00177     if (bhp_ == 0)
00178     {
00179         open();
00180     }
00181 
00182     ISC_STATUS stat[20];
00183     unsigned short bytes;
00184     std::vector<char>::size_type total_bytes = 0;
00185     bool keep_reading = false;
00186 
00187     do
00188     {
00189         bytes = 0;
00190         // next segment of data
00191         // data_ is large-enough because we know total size of blob
00192         isc_get_segment(stat, &bhp_, &bytes, static_cast<short>(max_seg_size_),
00193                         &data_[total_bytes]);
00194 
00195         total_bytes += bytes;
00196 
00197         if (total_bytes == data_.size())
00198         {
00199             // we have all BLOB data
00200             keep_reading = false;
00201         }
00202         else if (stat[1] == 0 || stat[1] == isc_segment)
00203         {
00204             // there is more data to read from current segment (0)
00205             // or there is next segment (isc_segment)
00206             keep_reading = true;
00207         }
00208         else if (stat[1] == isc_segstr_eof)
00209         {
00210             // BLOB is shorter then we expected ???
00211             keep_reading = false;
00212         }
00213         else
00214         {
00215             // an error has occured
00216             throw_iscerror(stat);
00217         }
00218     }
00219     while (keep_reading);
00220 
00221     loaded_ = true;
00222 }
00223 
00224 // this method saves BLOB content to database
00225 // (a new BLOB will be created at this point)
00226 // BLOB will be closed after save.
00227 void firebird_blob_backend::save()
00228 {
00229     // close old blob if necessary
00230     ISC_STATUS stat[20];
00231     if (bhp_ != 0)
00232     {
00233         if (isc_close_blob(stat, &bhp_))
00234         {
00235             throw_iscerror(stat);
00236         }
00237         bhp_ = 0;
00238     }
00239 
00240     // create new blob
00241     if (isc_create_blob(stat, &session_.dbhp_, &session_.trhp_,
00242                         &bhp_, &bid_))
00243     {
00244         throw_iscerror(stat);
00245     }
00246 
00247     if (data_.size() > 0)
00248     {
00249         // write data
00250         if (isc_put_segment(stat, &bhp_,
00251                             static_cast<unsigned short>(data_.size()), &data_[0]))
00252         {
00253             throw_iscerror(stat);
00254         }
00255     }
00256 
00257     cleanUp();
00258     from_db_ = true;
00259 }
00260 
00261 // retrives number of segments and total length of BLOB
00262 // returns total length of BLOB
00263 long firebird_blob_backend::getBLOBInfo()
00264 {
00265     char blob_items[] = {isc_info_blob_max_segment, isc_info_blob_total_length};
00266     char res_buffer[20], *p, item;
00267     short length;
00268     long total_length = 0;
00269 
00270     ISC_STATUS stat[20];
00271 
00272     if (isc_blob_info(stat, &bhp_, sizeof(blob_items), blob_items,
00273                       sizeof(res_buffer), res_buffer))
00274     {
00275         throw_iscerror(stat);
00276     }
00277 
00278     for (p = res_buffer; *p != isc_info_end ;)
00279     {
00280         item = *p++;
00281         length = static_cast<short>(isc_vax_integer(p, 2));
00282         p += 2;
00283         switch (item)
00284         {
00285             case isc_info_blob_max_segment:
00286                 max_seg_size_ = isc_vax_integer(p, length);
00287                 break;
00288             case isc_info_blob_total_length:
00289                 total_length = isc_vax_integer(p, length);
00290                 break;
00291             case isc_info_truncated:
00292                 throw soci_error("Fatal Error: BLOB info truncated!");
00293                 break;
00294             default:
00295                 break;
00296         }
00297         p += length;
00298     }
00299 
00300     return total_length;
00301 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1