src/db/bdb/bdb_types.cpp

Go to the documentation of this file.
00001 /*  $Id: bdb_types.cpp 163327 2009-06-15 15:40:12Z ivanovp $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author: Anatoliy Kuznetsov
00027  *
00028  * File Description:  BDB libarary types implementations.
00029  *
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 #include <corelib/ncbi_bswap.hpp>
00034 #include <db/bdb/bdb_types.hpp>
00035 #include <db.h>
00036 
00037 BEGIN_NCBI_SCOPE
00038 
00039 
00040 static
00041 const unsigned char* s_GetLString(const unsigned char* str,
00042                                   bool  check_legacy,
00043                                   int*  str_len)
00044 {
00045     _ASSERT(str);
00046     _ASSERT(str_len);
00047 
00048     // string length reconstruction
00049     *str_len = (str[0])       |
00050                (str[1] << 8)  |
00051                (str[2] << 16) |
00052                (str[3] << 24);
00053 
00054     if (check_legacy) {
00055         if (*str_len < 0) { // true L-string
00056             *str_len = -(*str_len);
00057             str += 4;
00058         } else {
00059             *str_len = ::strlen((const char*)str);
00060         }
00061     } else {  // no legacy strings
00062         if (*str_len <= 0) { // true L-string
00063             *str_len = -(*str_len);
00064             str += 4;
00065         } else {
00066             _ASSERT(0); // positive length !
00067         }
00068     }
00069 
00070     return str;
00071 
00072 }
00073 
00074 static
00075 const unsigned char* s_GetLString(const DBT* val,
00076                                   bool  check_legacy,
00077                                   int*  str_len)
00078 {
00079     const unsigned char* str = (const unsigned char*)val->data;
00080 
00081     if (val->size <= 4) {  // looks like legacy C-string
00082         _ASSERT(check_legacy);
00083         *str_len = ::strlen((const char*)str);
00084         return str;
00085     }
00086 
00087     return s_GetLString(str, check_legacy, str_len);
00088 }
00089 
00090 
00091 
00092 extern "C"
00093 {
00094 
00095 /////////////////////////////////////////////////////////////////////////////
00096 //  BDB comparison functions
00097 //
00098 
00099 int BDB_UintCompare(DB* db, const DBT* val1, const DBT* val2)
00100 {
00101     return BDB_Uint4Compare(db, val1, val2);
00102 }
00103 
00104 int BDB_Uint4Compare(DB*, const DBT* val1, const DBT* val2)
00105 {
00106     Uint4 v1, v2;
00107 #ifdef HAVE_UNALIGNED_READS
00108     v1 = *((Uint4*) val1->data);
00109     v2 = *((Uint4*) val2->data);
00110 #else
00111     ::memcpy(&v1, val1->data, sizeof(Uint4));
00112     ::memcpy(&v2, val2->data, sizeof(Uint4));
00113 #endif
00114     return (v1 < v2) ? -1
00115                      : ((v2 < v1) ? 1 : 0);
00116 }
00117 
00118 int BDB_Int8Compare(DB*, const DBT* val1, const DBT* val2)
00119 {
00120     Int8 v1, v2;
00121 #ifdef HAVE_UNALIGNED_READS
00122     v1 = *((Int8*) val1->data);
00123     v2 = *((Int8*) val2->data);
00124 #else
00125     ::memcpy(&v1, val1->data, sizeof(Int8));
00126     ::memcpy(&v2, val2->data, sizeof(Int8));
00127 #endif
00128     return (v1 < v2) ? -1
00129                      : ((v2 < v1) ? 1 : 0);
00130 }
00131 
00132 int BDB_Uint8Compare(DB*, const DBT* val1, const DBT* val2)
00133 {
00134     Uint8 v1, v2;
00135 #ifdef HAVE_UNALIGNED_READS
00136     v1 = *((Uint8*) val1->data);
00137     v2 = *((Uint8*) val2->data);
00138 #else
00139     ::memcpy(&v1, val1->data, sizeof(Uint8));
00140     ::memcpy(&v2, val2->data, sizeof(Uint8));
00141 #endif
00142     return (v1 < v2) ? -1
00143                      : ((v2 < v1) ? 1 : 0);
00144 }
00145 
00146 int BDB_IntCompare(DB* db, const DBT* val1, const DBT* val2)
00147 {
00148     return BDB_Int4Compare(db, val1, val2);
00149 }
00150 
00151 int BDB_Int4Compare(DB*, const DBT* val1, const DBT* val2)
00152 {
00153     Int4 v1, v2;
00154 #ifdef HAVE_UNALIGNED_READS
00155     v1 = *((Int4*) val1->data);
00156     v2 = *((Int4*) val2->data);
00157 #else
00158     ::memcpy(&v1, val1->data, sizeof(Int4));
00159     ::memcpy(&v2, val2->data, sizeof(Int4));
00160 #endif
00161     return (v1 < v2) ? -1
00162                      : ((v2 < v1) ? 1 : 0);
00163 }
00164 
00165 int BDB_Int2Compare(DB*, const DBT* val1, const DBT* val2)
00166 {
00167     Int2 v1, v2;
00168 #ifdef HAVE_UNALIGNED_READS
00169     v1 = *((Int2*) val1->data);
00170     v2 = *((Int2*) val2->data);
00171 #else
00172     ::memcpy(&v1, val1->data, sizeof(Int2));
00173     ::memcpy(&v2, val2->data, sizeof(Int2));
00174 #endif
00175     return (v1 < v2) ? -1
00176                      : ((v2 < v1) ? 1 : 0);
00177 }
00178 
00179 int BDB_Uint2Compare(DB*, const DBT* val1, const DBT* val2)
00180 {
00181     Uint2 v1, v2;
00182 #ifdef HAVE_UNALIGNED_READS
00183     v1 = *((Uint2*) val1->data);
00184     v2 = *((Uint2*) val2->data);
00185 #else
00186     ::memcpy(&v1, val1->data, sizeof(Uint2));
00187     ::memcpy(&v2, val2->data, sizeof(Uint2));
00188 #endif
00189     return (v1 < v2) ? -1
00190                      : ((v2 < v1) ? 1 : 0);
00191 }
00192 
00193 int BDB_CharCompare(DB*, const DBT* val1, const DBT* val2)
00194 {
00195     const char& v1=*static_cast<char*>(val1->data);
00196     const char& v2=*static_cast<char*>(val2->data);
00197 
00198     return (v1 < v2) ? -1
00199                      : ((v2 < v1) ? 1 : 0);
00200 }
00201 
00202 int BDB_UCharCompare(DB*, const DBT* val1, const DBT* val2)
00203 {
00204     const unsigned char& v1=*static_cast<unsigned char*>(val1->data);
00205     const unsigned char& v2=*static_cast<unsigned char*>(val2->data);
00206 
00207     return (v1 < v2) ? -1
00208                      : ((v2 < v1) ? 1 : 0);
00209 }
00210 
00211 int BDB_FloatCompare(DB*, const DBT* val1, const DBT* val2)
00212 {
00213     float v1, v2;
00214 #ifdef HAVE_UNALIGNED_READS
00215     v1 = *((float*) val1->data);
00216     v2 = *((float*) val2->data);
00217 #else
00218     ::memcpy(&v1, val1->data, sizeof(v1));
00219     ::memcpy(&v2, val2->data, sizeof(v2));
00220 #endif
00221     return (v1 < v2) ? -1
00222                      : ((v2 < v1) ? 1 : 0);
00223 }
00224 
00225 int BDB_DoubleCompare(DB*, const DBT* val1, const DBT* val2)
00226 {
00227     double v1, v2;
00228 #ifdef HAVE_UNALIGNED_READS
00229     v1 = *((double*) val1->data);
00230     v2 = *((double*) val2->data);
00231 #else
00232     ::memcpy(&v1, val1->data, sizeof(v1));
00233     ::memcpy(&v2, val2->data, sizeof(v2));
00234 #endif
00235     return (v1 < v2) ? -1
00236                      : ((v2 < v1) ? 1 : 0);
00237 }
00238 
00239 int BDB_StringCompare(DB*, const DBT* val1, const DBT* val2)
00240 {
00241     return ::strcmp((const char*)val1->data, (const char*)val2->data);
00242 }
00243 
00244 int BDB_FixedByteStringCompare(DB* db, const DBT* val1, const DBT* val2)
00245 {
00246     _ASSERT(val1->size == val2->size);
00247 
00248     int r = ::memcmp(val1->data, val2->data, val1->size);
00249     return r;
00250 }
00251 
00252 
00253 
00254 int BDB_LStringCompare(DB* db, const DBT* val1, const DBT* val2)
00255 {
00256     const CBDB_BufferManager* fbuf1 =
00257           static_cast<CBDB_BufferManager*> (db->app_private);
00258 
00259     bool check_legacy = fbuf1->IsLegacyStrings();
00260 
00261     const unsigned char* str1;
00262     const unsigned char* str2;
00263     int str_len1;
00264     int str_len2;
00265 
00266     str1 = s_GetLString(val1, check_legacy, &str_len1);
00267     str2 = s_GetLString(val2, check_legacy, &str_len2);
00268 
00269     int cmp_len = min(str_len1, str_len2);
00270     int r = ::memcmp(str1, str2, cmp_len);
00271     if (r == 0) {
00272         return (str_len1 < str_len2) ? -1
00273                                      : ((str_len2 < str_len1) ? 1 : 0);
00274     }
00275     return r;
00276 }
00277 
00278 
00279 int BDB_StringCaseCompare(DB*, const DBT* val1, const DBT* val2)
00280 {
00281     return NStr::strcasecmp((const char*)val1->data, (const char*)val2->data);
00282 }
00283 
00284 int BDB_Compare(DB* db, const DBT* val1, const DBT* val2)
00285 {
00286     const CBDB_BufferManager* fbuf1 =
00287           static_cast<CBDB_BufferManager*> (db->app_private);
00288 
00289     bool byte_swapped = fbuf1->IsByteSwapped();
00290 
00291     _ASSERT(fbuf1);
00292 
00293     const char* p1 = static_cast<char*> (val1->data);
00294     const char* p2 = static_cast<char*> (val2->data);
00295 
00296     unsigned int cmp_limit = fbuf1->GetFieldCompareLimit();
00297     if (cmp_limit == 0) {
00298         cmp_limit = fbuf1->FieldCount();
00299     } else {
00300         _ASSERT(cmp_limit <= fbuf1->FieldCount());
00301     }
00302 
00303     for (unsigned int i = 0;  i < cmp_limit;  ++i) {
00304         const CBDB_Field& fld1 = fbuf1->GetField(i);
00305         int ret = fld1.Compare(p1, p2, byte_swapped);
00306         if ( ret )
00307             return ret;
00308 
00309         p1 += fld1.GetDataLength(p1);
00310         p2 += fld1.GetDataLength(p2);
00311     }
00312 
00313     return 0;
00314 }
00315 
00316 /// String hash function taken from SStringHash (algo/text/text_util)
00317 /// @internal
00318 unsigned int
00319 BDB_Hash(DB *, const void *bytes, unsigned length)
00320 {
00321     const unsigned char* buf = (const unsigned char*)bytes;
00322     const unsigned char* buf_end = buf + length;
00323     // Copied from include/algo/text/text_util.hpp:StrngHash17
00324     // to cut dependency to algo
00325     unsigned ha = 0;
00326     for (; buf != buf_end; ++buf) {
00327         ha = ((ha << 4) + ha) + *buf;
00328     }
00329     return ha;
00330 }
00331 
00332 unsigned int
00333 BDB_Uint4Hash(DB *db, const void *bytes, unsigned length)
00334 {
00335     if (length == 4) {
00336         unsigned ha;
00337         ::memcpy(&ha, bytes, 4);
00338         return ha;
00339     } else {
00340         return BDB_Hash(db, bytes, length);
00341     }
00342 }
00343 
00344 
00345 
00346 int BDB_ByteSwap_UintCompare(DB* db, const DBT* val1, const DBT* val2)
00347 {
00348     return BDB_ByteSwap_Uint4Compare(db, val1, val2);
00349 }
00350 
00351 int BDB_ByteSwap_Uint4Compare(DB*, const DBT* val1, const DBT* val2)
00352 {
00353     unsigned int v1, v2;
00354     v1 = (unsigned int) CByteSwap::GetInt4((unsigned char*)val1->data);
00355     v2 = (unsigned int) CByteSwap::GetInt4((unsigned char*)val2->data);
00356     return (v1 < v2) ? -1
00357                      : ((v2 < v1) ? 1 : 0);
00358 }
00359 
00360 int BDB_ByteSwap_Int8Compare(DB*, const DBT* val1, const DBT* val2)
00361 {
00362     Int8 v1, v2;
00363     v1 = CByteSwap::GetInt8((unsigned char*)val1->data);
00364     v2 = CByteSwap::GetInt8((unsigned char*)val2->data);
00365     return (v1 < v2) ? -1
00366                      : ((v2 < v1) ? 1 : 0);
00367 }
00368 
00369 int BDB_ByteSwap_Uint8Compare(DB*, const DBT* val1, const DBT* val2)
00370 {
00371     Uint8 v1, v2;
00372     v1 = CByteSwap::GetInt8((unsigned char*)val1->data);
00373     v2 = CByteSwap::GetInt8((unsigned char*)val2->data);
00374     return (v1 < v2) ? -1
00375                      : ((v2 < v1) ? 1 : 0);
00376 }
00377 
00378 int BDB_ByteSwap_IntCompare(DB* db, const DBT* val1, const DBT* val2)
00379 {
00380     return BDB_ByteSwap_Int4Compare(db, val1, val2);
00381 }
00382 
00383 int BDB_ByteSwap_Int4Compare(DB*, const DBT* val1, const DBT* val2)
00384 {
00385     int v1, v2;
00386     v1 = CByteSwap::GetInt4((unsigned char*)val1->data);
00387     v2 = CByteSwap::GetInt4((unsigned char*)val2->data);
00388     return (v1 < v2) ? -1
00389                      : ((v2 < v1) ? 1 : 0);
00390 }
00391 
00392 int BDB_ByteSwap_Int2Compare(DB*, const DBT* val1, const DBT* val2)
00393 {
00394     Int2 v1, v2;
00395     v1 = CByteSwap::GetInt2((unsigned char*)val1->data);
00396     v2 = CByteSwap::GetInt2((unsigned char*)val2->data);
00397     return (v1 < v2) ? -1
00398                      : ((v2 < v1) ? 1 : 0);
00399 }
00400 
00401 int BDB_ByteSwap_Uint2Compare(DB*, const DBT* val1, const DBT* val2)
00402 {
00403     Uint2 v1, v2;
00404     v1 = CByteSwap::GetInt2((unsigned char*)val1->data);
00405     v2 = CByteSwap::GetInt2((unsigned char*)val2->data);
00406     return (v1 < v2) ? -1
00407                      : ((v2 < v1) ? 1 : 0);
00408 }
00409 
00410 
00411 int BDB_ByteSwap_FloatCompare(DB*, const DBT* val1, const DBT* val2)
00412 {
00413     float v1, v2;
00414     v1 = CByteSwap::GetFloat((unsigned char*)val1->data);
00415     v2 = CByteSwap::GetFloat((unsigned char*)val2->data);
00416     return (v1 < v2) ? -1
00417                      : ((v2 < v1) ? 1 : 0);
00418 }
00419 
00420 
00421 int BDB_ByteSwap_DoubleCompare(DB*, const DBT* val1, const DBT* val2)
00422 {
00423     double v1, v2;
00424     v1 = CByteSwap::GetDouble((unsigned char*)val1->data);
00425     v2 = CByteSwap::GetDouble((unsigned char*)val2->data);
00426     return (v1 < v2) ? -1
00427                      : ((v2 < v1) ? 1 : 0);
00428 
00429 }
00430 
00431 
00432 
00433 
00434 } // extern "C"
00435 
00436 /////////////////////////////////////////////////////////////////////////////
00437 //  IBDB_Field::
00438 //
00439 
00440 IBDB_Field::~IBDB_Field()
00441 {
00442 }
00443 
00444 /////////////////////////////////////////////////////////////////////////////
00445 //  CBDB_Field::
00446 //
00447 
00448 CBDB_Field::CBDB_Field(ELengthType length_type)
00449 : m_BufferManager(0),
00450   m_Buffer(0),
00451   m_BufferSize(0),
00452   m_BufferIdx(0)
00453 {
00454     m_Flags.VariableLength = (length_type == eFixedLength) ? 0 : 1;
00455     m_Flags.Attached = 0;
00456     m_Flags.Nullable = 0;
00457 }
00458 
00459 BDB_CompareFunction
00460 CBDB_Field::GetCompareFunction(bool /*byte_swapped*/) const
00461 {
00462     return BDB_Compare;
00463 }
00464 
00465 
00466 size_t CBDB_Field::GetExtraDataLength()
00467 {
00468     return 0;
00469 }
00470 
00471 
00472 /////////////////////////////////////////////////////////////////////////////
00473 //  CBDB_BufferManager::
00474 //
00475 
00476 
00477 CBDB_BufferManager::CBDB_BufferManager()
00478   : m_Buffer(0),
00479     m_BufferSize(0),
00480     m_PackedSize(0),
00481     m_DBT_Size(0),
00482     m_Packable(false),
00483     m_ByteSwapped(false),
00484     m_Nullable(false),
00485     m_NullSetSize(0),
00486     m_CompareLimit(0),
00487     m_LegacyString(false),
00488     m_OwnFields(false),
00489     m_PackOptComputed(false),
00490     m_FirstVarFieldIdx(0),
00491     m_FirstVarFieldIdxOffs(0)
00492 {
00493 }
00494 
00495 CBDB_BufferManager::~CBDB_BufferManager()
00496 {
00497     delete [] m_Buffer;
00498 
00499     if (m_OwnFields) {
00500         for (size_t i = 0;  i < m_Fields.size(); ++i) {
00501             CBDB_Field* field = m_Fields[i];
00502             delete field;
00503         }
00504     }
00505 }
00506 
00507 void CBDB_BufferManager::Bind(CBDB_Field* field, ENullable is_nullable)
00508 {
00509     m_Fields.push_back(field);
00510     m_Ptrs.push_back(0);
00511 
00512     unsigned field_idx = (unsigned)(m_Fields.size() - 1);
00513     field->SetBufferIdx(field_idx);
00514 
00515     if ( !m_Packable ) {
00516         // If we bind any var length field, then record becomes packable
00517         m_Packable = field->IsVariableLength();
00518     }
00519 
00520     if (is_nullable == eNullable)
00521         field->SetNullable();
00522 }
00523 
00524 int CBDB_BufferManager::GetFieldIndex(const string& name) const
00525 {
00526     for (size_t i = 0;  i < m_Fields.size();  ++i) {
00527         const CBDB_Field& field = *m_Fields[i];
00528         const string& fname = field.GetName();
00529         if (NStr::CompareNocase(name, fname) == 0) {
00530             return i;
00531         }
00532     }
00533     return -1;
00534 }
00535 
00536 size_t CBDB_BufferManager::ComputeBufferSize() const
00537 {
00538     size_t buf_len = 0;
00539     for (size_t i = 0;  i < m_Fields.size();  ++i) {
00540         const CBDB_Field& field = *m_Fields[i];
00541         buf_len += field.GetBufferSize();
00542     }
00543     return buf_len;
00544 }
00545 
00546 
00547 void CBDB_BufferManager::CheckNullConstraint() const
00548 {
00549     if ( !IsNullable() )
00550         return;
00551 
00552     for (size_t i = 0;  i < m_Fields.size();  ++i) {
00553         const CBDB_Field& fld = *m_Fields[i];
00554         if (!fld.IsNullable()  &&  TestNullBit((unsigned)i)) {
00555             string message("NULL field in database operation.");
00556             const string& field_name = fld.GetName();
00557             if ( !field_name.empty() ) {
00558                 message.append("(Field:");
00559                 message.append(field_name);
00560                 message.append(")");
00561             }
00562             BDB_THROW(eNull, message);
00563         }
00564     }
00565 }
00566 
00567 
00568 void CBDB_BufferManager::Construct()
00569 {
00570     _ASSERT(m_Fields.size());
00571 
00572     // Buffer construction: fields size calculation.
00573     m_BufferSize = ComputeBufferSize();
00574 
00575     if ( IsNullable() ) {
00576         m_NullSetSize = ComputeNullSetSize();
00577         m_BufferSize += m_NullSetSize;
00578     }
00579 
00580     delete [] m_Buffer; m_Buffer = 0;
00581     m_Buffer = new char[m_BufferSize];
00582     ::memset(m_Buffer, 0, m_BufferSize);
00583 
00584     // Record construction: set element offsets(pointers)
00585     char*  buf_ptr = (char*) m_Buffer;
00586     buf_ptr += m_NullSetSize;
00587 
00588     for (size_t i = 0;  i < m_Fields.size();  ++i) {
00589         CBDB_Field& df = *m_Fields[i];
00590         m_Ptrs[i] = buf_ptr;
00591 
00592         df.SetBufferManager(this);
00593         df.SetBuffer(buf_ptr);
00594 
00595         buf_ptr += df.GetBufferSize();
00596     }
00597 
00598     m_PackedSize = 0;  // not packed
00599 }
00600 
00601 
00602 BDB_CompareFunction
00603 CBDB_BufferManager::GetCompareFunction() const
00604 {
00605     if (m_Fields.size() > 1)
00606         return BDB_Compare;
00607     bool byte_swapped = IsByteSwapped();
00608     return m_Fields[0]->GetCompareFunction(byte_swapped);
00609 }
00610 
00611 
00612 BDB_HashFunction
00613 CBDB_BufferManager::GetHashFunction() const
00614 {
00615     return BDB_Hash;
00616 }
00617 
00618 
00619 void CBDB_BufferManager::ArrangePtrsPacked()
00620 {
00621     _ASSERT(m_Fields.size());
00622 
00623     if ( !IsPackable() ) {
00624         m_PackedSize = m_BufferSize;
00625         return;
00626     }
00627 
00628     char* buf_ptr = m_Buffer;
00629     buf_ptr += m_NullSetSize;
00630     m_PackedSize = m_NullSetSize;
00631 
00632     for (size_t i = 0;  i < m_Fields.size();  ++i) {
00633         CBDB_Field& df = *m_Fields[i];
00634         df.SetBuffer(buf_ptr);
00635         size_t len = df.GetDataLength(buf_ptr);
00636         buf_ptr += len;
00637         m_PackedSize += len;
00638     }
00639 }
00640 
00641 void CBDB_BufferManager::x_ComputePackOpt()
00642 {
00643     unsigned int offset = m_NullSetSize;
00644 
00645     for (TFieldVector::size_type i = 0;  i < m_Fields.size();  ++i) {
00646         CBDB_Field& df = *m_Fields[i];
00647 
00648         if (df.IsVariableLength()) {
00649             m_FirstVarFieldIdx = i;
00650             break;
00651         }
00652 
00653         size_t actual_len = df.GetLength();
00654         offset += actual_len;
00655     } // for
00656 
00657     m_FirstVarFieldIdxOffs = offset;
00658     m_PackOptComputed = true;
00659 }
00660 
00661 
00662 unsigned int CBDB_BufferManager::Pack()
00663 {
00664     _ASSERT(m_Fields.size());
00665     if (m_PackedSize != 0)
00666         return (unsigned)m_PackedSize;
00667     if ( !IsPackable() ) {
00668         m_PackedSize = m_BufferSize;
00669         return (unsigned)m_PackedSize;
00670     }
00671 
00672     if (!m_PackOptComputed) {
00673         x_ComputePackOpt();
00674     }
00675 
00676     char* new_ptr = m_Buffer;
00677     new_ptr += m_FirstVarFieldIdxOffs;
00678     m_PackedSize = m_FirstVarFieldIdxOffs;
00679 
00680     for (size_t i = m_FirstVarFieldIdx;  i < m_Fields.size();  ++i) {
00681         CBDB_Field& df = *m_Fields[i];
00682         size_t actual_len = df.GetLength();
00683         void* old_ptr = m_Ptrs[i];
00684 
00685         if (new_ptr != old_ptr) {
00686             ::memmove(new_ptr, old_ptr, actual_len);
00687             df.SetBuffer(new_ptr);
00688         }
00689 
00690         if ( m_NullSetSize ) {
00691             if (df.IsVariableLength()  &&  TestNullBit((unsigned)i)) {
00692                 actual_len = 1;
00693                 *new_ptr = '\0'; // for string it will guarantee it is empty
00694             }
00695         }
00696 
00697         new_ptr      += actual_len;
00698         m_PackedSize += actual_len;
00699     }
00700 
00701     return (unsigned)m_PackedSize;
00702 }
00703 
00704 
00705 unsigned int CBDB_BufferManager::Unpack()
00706 {
00707     _ASSERT(m_Fields.size());
00708     if (m_PackedSize == 0)
00709         return (unsigned)m_BufferSize;
00710     if ( !IsPackable() ) {
00711         m_PackedSize = 0;
00712         return (unsigned)m_PackedSize;
00713     }
00714     if (!m_PackOptComputed) {
00715         x_ComputePackOpt();
00716     }
00717 
00718     _ASSERT(!m_Fields.empty());
00719     for (size_t i = m_Fields.size() - 1;  true;  --i) {
00720         CBDB_Field& df = *m_Fields[i];
00721         size_t actual_len = df.GetLength();
00722         void* new_ptr = m_Ptrs[i];
00723         const void* old_ptr = df.GetBuffer();
00724         if (new_ptr != old_ptr) {
00725             ::memmove(new_ptr, old_ptr, actual_len);
00726             df.SetBuffer(new_ptr);
00727         }
00728         m_PackedSize -= actual_len;
00729 
00730         if (i == m_FirstVarFieldIdx) {
00731             m_PackedSize -= m_FirstVarFieldIdxOffs;
00732             break;
00733         }
00734     }
00735 
00736 
00737     _ASSERT(m_PackedSize == 0);
00738     return (unsigned)m_BufferSize;
00739 }
00740 
00741 void CBDB_BufferManager::PrepareDBT_ForWrite(DBT* dbt)
00742 {
00743     Pack();
00744     dbt->data = m_Buffer;
00745     dbt->size = (unsigned)m_PackedSize;
00746     dbt->ulen = (unsigned)m_BufferSize;
00747     dbt->flags = DB_DBT_USERMEM;
00748 }
00749 
00750 void CBDB_BufferManager::PrepareDBT_ForRead(DBT* dbt)
00751 {
00752     dbt->data = m_Buffer;
00753     dbt->size = (unsigned)m_PackedSize;
00754     dbt->ulen = (unsigned)m_BufferSize;
00755     dbt->flags = DB_DBT_USERMEM;
00756 }
00757 
00758 int
00759 CBDB_BufferManager::Compare(const CBDB_BufferManager& buf_mgr,
00760                             unsigned int              field_count) const
00761 {
00762     if ( !field_count ) {
00763         field_count = FieldCount();
00764     }
00765     _ASSERT(field_count <= FieldCount());
00766 
00767     for (unsigned int i = 0;  i < field_count;  ++i) {
00768         const CBDB_Field& df1 = GetField(i);
00769         const CBDB_Field& df2 = buf_mgr.GetField(i);
00770 
00771         int ret = df1.CompareWith(df2);
00772         if ( ret )
00773             return ret;
00774     }
00775 
00776     return 0;
00777 }
00778 
00779 
00780 void CBDB_BufferManager::DuplicateStructureFrom(const CBDB_BufferManager& buf_mgr)
00781 {
00782     _ASSERT(FieldCount() == 0);
00783     for (unsigned int i = 0;  i < buf_mgr.FieldCount();  ++i) {
00784         const CBDB_Field& src_fld = buf_mgr.GetField(i);
00785 
00786         // "0" value selects the same buffer size as in src_fld
00787         auto_ptr<CBDB_Field> dst_fld(src_fld.Construct(0));
00788 
00789         dst_fld->SetName(src_fld.GetName().c_str());
00790         Bind(dst_fld.get());
00791         dst_fld.release();
00792     }
00793     m_LegacyString = buf_mgr.IsLegacyStrings();
00794 }
00795 
00796 
00797 void CBDB_BufferManager::CopyFrom(const CBDB_BufferManager& buf_mgr)
00798 {
00799     CopyFieldsFrom(buf_mgr);
00800 }
00801 
00802 void CBDB_BufferManager::CopyPackedFrom(void* data, size_t data_size)
00803 {
00804     _ASSERT(data);
00805     _ASSERT(data_size <= m_BufferSize);
00806 
00807     memcpy(m_Buffer, data, data_size);
00808     SetDBT_Size(data_size);
00809     ArrangePtrsPacked();
00810 }
00811 
00812 /////////////////////////////////////////////////////////////////////////////
00813 //  CBDB_FieldFixedByteString::
00814 //
00815 
00816 CBDB_FieldFixedByteString::CBDB_FieldFixedByteString()
00817     : CBDB_Field(eFixedLength)
00818 {
00819     SetBufferSize(256 + 4);
00820 }
00821 
00822 CBDB_FieldFixedByteString&
00823 CBDB_FieldFixedByteString::operator=(const CBDB_FieldFixedByteString& str)
00824 {
00825     void* buf = GetBuffer();
00826     if (this == &str)
00827         return *this;
00828 
00829     size_t len = str.GetDataLength(buf);
00830     if ( len > (GetBufferSize()) ) {
00831         // TODO: allow partial string assignment?
00832         BDB_THROW(eOverflow, "Fixed string field overflow.");
00833     }
00834     Unpack();
00835     ::memcpy(buf, str.GetBuffer(), len);
00836 
00837     if ( str.IsNull() ) {
00838         SetNull();
00839     } else {
00840         SetNotNull();
00841     }
00842 
00843     return *this;
00844 }
00845 
00846 
00847 
00848 
00849 /////////////////////////////////////////////////////////////////////////////
00850 //  CBDB_FieldLString::
00851 //
00852 
00853 CBDB_FieldLString::CBDB_FieldLString()
00854  : CBDB_FieldStringBase()
00855 {
00856     SetBufferSize(256 + 4);
00857 }
00858 
00859 CBDB_Field* CBDB_FieldLString::Construct(size_t buf_size) const
00860 {
00861     CBDB_FieldLString* fld = new CBDB_FieldLString();
00862     fld->SetBufferSize(buf_size ? buf_size + 4 : GetBufferSize());
00863     return fld;
00864 }
00865 
00866 
00867 const unsigned char*
00868 CBDB_FieldLString::GetLString(const unsigned char* str,
00869                               bool                 check_legacy,
00870                               int*                 str_len) const
00871 {
00872     size_t DBT_size = m_BufferManager->GetDBT_Size();
00873 
00874     if (DBT_size > 0 && DBT_size <= 4) {  // looks like legacy C-string
00875         _ASSERT(check_legacy);
00876         *str_len = (int)::strlen((const char*)str);
00877     } else {
00878         str = s_GetLString(str, check_legacy, str_len);
00879     }
00880     return str;
00881 }
00882 
00883 
00884 size_t CBDB_FieldLString::GetExtraDataLength()
00885 {
00886     return 4;
00887 }
00888 
00889 
00890 /*
00891 CBDB_FieldLString::operator const char* () const
00892 {
00893     const unsigned char* str = (const unsigned char*)GetBuffer();
00894     bool check_legacy = m_BufferManager->IsLegacyStrings();
00895 
00896     int str_len;
00897     size_t DBT_size = m_BufferManager->GetDBT_Size();
00898 
00899     if (DBT_size <= 4) {  // looks like legacy C-string
00900         _ASSERT(check_legacy);
00901         str_len = ::strlen((const char*)str);
00902     } else {
00903         str = GetLString(str, check_legacy, &str_len);
00904     }
00905     return (const char*) str;
00906 }
00907 */
00908 
00909 CBDB_FieldLString&
00910 CBDB_FieldLString::operator=(const CBDB_FieldLString& str)
00911 {
00912     void* buf = GetBuffer();
00913     if (this == &str)
00914         return *this;
00915 
00916     size_t len = str.GetDataLength(buf);
00917     if ( len > (GetBufferSize() - 4) ) {
00918         // TODO: allow partial string assignment?
00919         BDB_THROW(eOverflow, "String field overflow.");
00920     }
00921     Unpack();
00922     ::memcpy(buf, str.GetBuffer(), len);
00923 
00924     if ( str.IsNull() ) {
00925         SetNull();
00926     } else {
00927         SetNotNull();
00928     }
00929 
00930     return *this;
00931 }
00932 
00933 void CBDB_FieldLString::Set(const char* str, size_t size,
00934                             EOverflowAction if_overflow)
00935 {
00936     if ( !size )
00937         str = kEmptyCStr;
00938 
00939     unsigned int new_len = (unsigned)size;
00940 
00941     // check overflow
00942     unsigned eff_buffer_size = GetBufferSize() - 4;
00943     if (new_len > eff_buffer_size) {
00944         if (if_overflow == eTruncateOnOverflow) {
00945             new_len = eff_buffer_size;
00946         } else {
00947             string message("String field overflow. Max length is ");
00948             message += NStr::IntToString(eff_buffer_size);
00949             message += ", requested length is ";
00950             message += NStr::IntToString(new_len);
00951             BDB_THROW(eOverflow, message);
00952         }
00953     }
00954     Unpack();
00955     unsigned char* str_buf = (unsigned char*) GetBuffer();
00956 
00957     int s_len = -(int)new_len;  // always store it negative
00958     str_buf[0] = (unsigned char) (s_len);
00959     str_buf[1] = (unsigned char) (s_len >> 8);
00960     str_buf[2] = (unsigned char) (s_len >> 16);
00961     str_buf[3] = (unsigned char) (s_len >> 24);
00962 
00963     str_buf += 4;
00964 
00965     ::memcpy(str_buf, str, new_len);
00966 
00967     SetNotNull();
00968 }
00969 
00970 
00971 void CBDB_FieldLString::Set(const char* str, EOverflowAction if_overflow)
00972 {
00973     if ( !str )
00974         str = kEmptyCStr;
00975 
00976     this->Set(str, ::strlen(str), if_overflow);
00977 }
00978 
00979 void CBDB_FieldLString::SetString(const char* str)
00980 {
00981     operator=(str);
00982 }
00983 
00984 
00985 int CBDB_FieldLString::Compare(const void* p1,
00986                                const void* p2,
00987                                bool /*byte_swapped*/) const
00988 {
00989     _ASSERT(p1 && p2);
00990 
00991     bool check_legacy = m_BufferManager->IsLegacyStrings();
00992 
00993     const unsigned char* str1;
00994     const unsigned char* str2;
00995     int str_len1;
00996     int str_len2;
00997 
00998     str1 = GetLString((const unsigned char*)p1, check_legacy, &str_len1);
00999     str2 = GetLString((const unsigned char*)p2, check_legacy, &str_len2);
01000 
01001     int cmp_len = min(str_len1, str_len2);
01002     int r = ::memcmp(str1, str2, cmp_len);
01003     if (r == 0) {
01004         return (str_len1 < str_len2) ? -1
01005                                      : ((str_len2 < str_len1) ? 1 : 0);
01006     }
01007     return r;
01008 }
01009 
01010 
01011 void CBDB_FieldLString::SetMinVal()
01012 {
01013     Set("", eTruncateOnOverflow);
01014 }
01015 
01016 
01017 void CBDB_FieldLString::SetMaxVal()
01018 {
01019     void* buf = Unpack();
01020     int buf_size = GetBufferSize();
01021 
01022     ::memset(buf, 0x7F, buf_size); // 0xFF for international
01023     ((char*) buf)[buf_size - 1] = '\0';
01024 
01025     int s_len = -(buf_size - 4);  // always store it negative
01026     unsigned char* str_buf = (unsigned char*) buf;
01027 
01028     str_buf[0] = (unsigned char) (s_len);
01029     str_buf[1] = (unsigned char) (s_len >> 8);
01030     str_buf[2] = (unsigned char) (s_len >> 16);
01031     str_buf[3] = (unsigned char) (s_len >> 24);
01032 
01033     SetNotNull();
01034 }
01035 
01036 
01037 bool CBDB_FieldLString::IsEmpty() const
01038 {
01039     const unsigned char* str = (const unsigned char*) GetBuffer();
01040     bool check_legacy = m_BufferManager->IsLegacyStrings();
01041     int str_len;
01042 
01043     str = GetLString(str, check_legacy, &str_len);
01044 
01045     return (str_len == 0);
01046 }
01047 
01048 bool CBDB_FieldLString::IsBlank() const
01049 {
01050     const unsigned char* str = (const unsigned char*) GetBuffer();
01051     bool check_legacy = m_BufferManager->IsLegacyStrings();
01052     int str_len;
01053 
01054     str = GetLString(str, check_legacy, &str_len);
01055 
01056     for (int i = 0; i < str_len; ++i) {
01057         if (!isspace((unsigned char) str[i]))
01058             return false;
01059     }
01060 
01061     return true;
01062 }
01063 
01064 
01065 size_t CBDB_FieldLString::GetDataLength(const void* buf) const
01066 {
01067     const unsigned char* str = (const unsigned char*) buf;
01068     bool check_legacy = m_BufferManager->IsLegacyStrings();
01069     int str_len;
01070 
01071     str = GetLString(str, check_legacy, &str_len);
01072     if (str != (const unsigned char*) buf)
01073         str_len += 4;
01074     // We should NOT add 1 to the length here because it messes with
01075     // buffer packing/unpacking algorithm for the record containing
01076     // this field.
01077     return str_len;
01078 }
01079 
01080 CBDB_FieldLString& CBDB_FieldLString::operator= (const char* str)
01081 {
01082     Set(str, eThrowOnOverflow);
01083     return *this;
01084 }
01085 
01086 CBDB_FieldLString& CBDB_FieldLString::operator= (const string& str)
01087 {
01088     SetStdString(str);
01089     return *this;
01090 }
01091 
01092 
01093 string CBDB_FieldLString::Get() const
01094 {
01095     _ASSERT(!IsNull());
01096 
01097     const unsigned char* buf = (const unsigned char*) GetBuffer();
01098     bool check_legacy = m_BufferManager->IsLegacyStrings();
01099 
01100     const unsigned char* str;
01101     int str_len;
01102 
01103     str = GetLString(buf, check_legacy, &str_len);
01104     if (str_len == 0) {
01105         return kEmptyStr;
01106     }
01107     string ret((const char*) str, str_len);
01108     return ret;
01109 }
01110 
01111 void CBDB_FieldLString::ToString(string& ostr) const
01112 {
01113     const unsigned char* buf = (const unsigned char*) GetBuffer();
01114     bool check_legacy = m_BufferManager->IsLegacyStrings();
01115 
01116     const unsigned char* str;
01117     int str_len;
01118 
01119     ostr.resize(0);
01120 
01121     str = GetLString(buf, check_legacy, &str_len);
01122     if (str_len == 0) {
01123         return;
01124     }
01125     ostr.append((const char*) str, str_len);
01126 }
01127 
01128 void CBDB_FieldLString::SetStdString(const string& str)
01129 {
01130     unsigned int str_len = str.length();
01131     if (str_len == 0) {
01132         Set("", eThrowOnOverflow);
01133         return;
01134     }
01135 
01136     unsigned eff_buffer_size = GetBufferSize() - 4;
01137     // check overflow
01138     if (str_len > eff_buffer_size) {
01139         string message("String field overflow. Max length is ");
01140         message += NStr::IntToString(eff_buffer_size);
01141         message += ", requested length is ";
01142         message += NStr::IntToString(str_len);
01143         BDB_THROW(eOverflow, message);
01144     }
01145 
01146     const char* str_data = str.data();
01147 
01148     unsigned char* str_buf = (unsigned char*) Unpack();
01149 
01150     int s_len = -(int)str_len;  // always store it negative
01151     str_buf[0] = (unsigned char) (s_len);
01152     str_buf[1] = (unsigned char) (s_len >> 8);
01153     str_buf[2] = (unsigned char) (s_len >> 16);
01154     str_buf[3] = (unsigned char) (s_len >> 24);
01155 
01156     str_buf += 4;
01157 
01158     ::memcpy(str_buf, str_data, str_len);
01159 
01160     SetNotNull();
01161 }
01162 
01163 /////////////////////////////////////////////////////////////////////////////
01164 //  CBDB_FieldFactory::
01165 //
01166 
01167 CBDB_FieldFactory::CBDB_FieldFactory()
01168 {}
01169 
01170 CBDB_FieldFactory::EType CBDB_FieldFactory::GetType(const string& type) const
01171 {
01172     if (NStr::CompareNocase(type, "string")==0) {
01173         return eString;
01174     } else
01175     if (NStr::CompareNocase(type, "lstring")==0) {
01176         return eLString;
01177     } else
01178     if (NStr::CompareNocase(type, "int8")==0) {
01179         return eInt8;
01180     } else
01181     if (NStr::CompareNocase(type, "int4")==0) {
01182         return eInt4;
01183     } else
01184     if (NStr::CompareNocase(type, "uint4")==0) {
01185         return eUint4;
01186     } else
01187     if (NStr::CompareNocase(type, "int2")==0) {
01188         return eInt2;
01189     } else
01190     if (NStr::CompareNocase(type, "uint1")==0) {
01191         return eUint1;
01192     } else
01193     if (NStr::CompareNocase(type, "float")==0) {
01194         return eFloat;
01195     } else
01196     if (NStr::CompareNocase(type, "double")==0) {
01197         return eDouble;
01198     } else
01199     if (NStr::CompareNocase(type, "uchar")==0) {
01200         return eUChar;
01201     } else
01202     if (NStr::CompareNocase(type, "blob")==0) {
01203         return eBlob;
01204     } else
01205     if (NStr::CompareNocase(type, "lob")==0) {
01206         return eBlob;
01207     } else {
01208         return eUnknown;
01209     }
01210 }
01211 
01212 CBDB_Field* CBDB_FieldFactory::Create(EType etype) const
01213 {
01214     switch (etype)
01215     {
01216     case eString:
01217         return new CBDB_FieldString();
01218     case eLString:
01219         return new CBDB_FieldLString();
01220     case eInt8:
01221         return new CBDB_FieldInt8();
01222     case eInt4:
01223         return new CBDB_FieldInt4();
01224     case eInt2:
01225         return new CBDB_FieldInt2();
01226     case eUint1:
01227         return new CBDB_FieldUint1();
01228     case eFloat:
01229         return  new CBDB_FieldFloat();
01230     case eDouble:
01231         return new CBDB_FieldDouble();
01232     case eUChar:
01233         return new CBDB_FieldUChar();
01234     default:
01235         BDB_THROW(eInvalidType, "Type is not supported.");
01236     };
01237 
01238     return 0;
01239 }
01240 
01241 CBDB_Field* CBDB_FieldFactory::Create(const string& type) const
01242 {
01243     EType et = GetType(type);
01244     try
01245     {
01246         return Create(et);
01247     }
01248     catch (CBDB_LibException& )
01249     {
01250         BDB_THROW(eInvalidType, type);
01251     }
01252 }
01253 
01254 
01255 END_NCBI_SCOPE
01256 
01257 
01258 
01259 

Generated on Sun Dec 6 22:22:47 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:58 2009 by modify_doxy.py rev. 173732