diff --git a/src/common/classes/Hash.cpp b/src/common/classes/Hash.cpp index afe31c9a84..605088fa06 100644 --- a/src/common/classes/Hash.cpp +++ b/src/common/classes/Hash.cpp @@ -108,3 +108,26 @@ unsigned int InternalHash::hash(unsigned int length, const UCHAR* value) { return internalHash(length, value); } + + +void WeakHashContext::update(const void* data, FB_SIZE_T length) +{ + const UCHAR* p = static_cast(data); + + for (const UCHAR* end = p + length; p != end; ++p) + { + hashNumber = (hashNumber << 4) + *p; + + const SINT64 n = hashNumber & FB_CONST64(0xF000000000000000); + if (n) + hashNumber ^= n >> 56; + + hashNumber &= ~n; + } +} + +void WeakHashContext::finish(Buffer& result) +{ + UCHAR* resultBuffer = result.getBuffer(sizeof(hashNumber)); + memcpy(resultBuffer, &hashNumber, sizeof(hashNumber)); +} diff --git a/src/common/classes/Hash.h b/src/common/classes/Hash.h index 39aaa5b46f..b0ee25052f 100644 --- a/src/common/classes/Hash.h +++ b/src/common/classes/Hash.h @@ -28,7 +28,7 @@ #ifndef CLASSES_HASH_H #define CLASSES_HASH_H -#include "../common/classes/vector.h" +#include "../common/classes/array.h" namespace Firebird { @@ -341,7 +341,31 @@ namespace Firebird } }; + + class HashContext + { + public: + typedef HalfStaticArray Buffer; + + public: + virtual ~HashContext() + { + } + + public: + virtual void update(const void* data, FB_SIZE_T length) = 0; + virtual void finish(Buffer& result) = 0; + }; + + class WeakHashContext FB_FINAL : public HashContext + { + public: + virtual void update(const void* data, FB_SIZE_T length); + virtual void finish(Buffer& result); + + private: + SINT64 hashNumber = 0; + }; } // namespace Firebird #endif // CLASSES_HASH_H - diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index a72f23bf66..16e6ded39e 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -30,6 +30,7 @@ #include "firebird.h" #include "../common/classes/VaryStr.h" +#include "../common/classes/Hash.h" #include "../jrd/SysFunction.h" #include "../jrd/DataTypeUtil.h" #include "../include/fb_blk.h" @@ -2647,10 +2648,9 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args, if (request->req_flags & req_null) // return NULL if value is NULL return NULL; + WeakHashContext hashContext; impure->vlu_misc.vlu_int64 = 0; - UCHAR* address; - if (value->isBlob()) { UCHAR buffer[BUFFER_LARGE]; @@ -2659,38 +2659,26 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args, while (!(blob->blb_flags & BLB_eof)) { - address = buffer; - const ULONG length = blob->BLB_get_data(tdbb, address, sizeof(buffer), false); - - for (const UCHAR* end = address + length; address < end; ++address) - { - impure->vlu_misc.vlu_int64 = (impure->vlu_misc.vlu_int64 << 4) + *address; - - const SINT64 n = impure->vlu_misc.vlu_int64 & FB_CONST64(0xF000000000000000); - if (n) - impure->vlu_misc.vlu_int64 ^= n >> 56; - impure->vlu_misc.vlu_int64 &= ~n; - } + const ULONG length = blob->BLB_get_data(tdbb, buffer, sizeof(buffer), false); + hashContext.update(buffer, length); } blob->BLB_close(tdbb); } else { + UCHAR* address; MoveBuffer buffer; const ULONG length = MOV_make_string2(tdbb, value, value->getTextType(), &address, buffer, false); - - for (const UCHAR* end = address + length; address < end; ++address) - { - impure->vlu_misc.vlu_int64 = (impure->vlu_misc.vlu_int64 << 4) + *address; - - const SINT64 n = impure->vlu_misc.vlu_int64 & FB_CONST64(0xF000000000000000); - if (n) - impure->vlu_misc.vlu_int64 ^= n >> 56; - impure->vlu_misc.vlu_int64 &= ~n; - } + hashContext.update(address, length); } + HashContext::Buffer resultBuffer; + hashContext.finish(resultBuffer); + + fb_assert(resultBuffer.getCount() == sizeof(SINT64)); + memcpy(&impure->vlu_misc.vlu_int64, resultBuffer.begin(), sizeof(SINT64)); + // make descriptor for return value impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64);