mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:03:03 +01:00
Support for different hashes algorithms in HASH system function.
This commit is contained in:
parent
987e85f676
commit
3a1a9b9d48
@ -68,6 +68,10 @@
|
||||
* [CORE-5064](http://tracker.firebirdsql.org/browse/CORE-5064): Add datatypes (VAR)BINARY(n) and BINARY VARYING(n) as aliases for (VAR)CHAR(n) CHARACTER SET OCTETS
|
||||
Contributor(s): Dimitry Sibiryakov
|
||||
|
||||
* [CORE-4436](http://tracker.firebirdsql.org/browse/CORE-4436): Support for different hash algorithms in HASH system function
|
||||
Reference(s): [doc/sql.extensions/README.builtin_functions.txt](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.builtin_functions.txt)
|
||||
Contributor(s): Adriano dos Santos Fernandes
|
||||
|
||||
* [CORE-2557](http://tracker.firebirdsql.org/browse/CORE-2557): Grants on MON$ tables
|
||||
Contributor(s): Alex Peshkoff
|
||||
|
||||
|
@ -473,13 +473,21 @@ HASH
|
||||
----
|
||||
|
||||
Function:
|
||||
Returns a HASH of a string.
|
||||
Returns a HASH of a string using a specified algorithm.
|
||||
|
||||
Format:
|
||||
HASH( <string> )
|
||||
HASH( <string> [ USING <algorithm> ] )
|
||||
|
||||
algorithm ::= { MD5 | SHA1 | SHA256 | SHA512 }
|
||||
|
||||
Important:
|
||||
- The syntax without USING is very discouraged and maintained for backward compatibility.
|
||||
It returns a 64 bit integer and produces very bad hashes that easily result in collisions.
|
||||
- The syntax with USING is introduced in FB 4.0 and returns VARCHAR strings with OCTETS charset.
|
||||
|
||||
Example:
|
||||
select hash(x) from y;
|
||||
select hash(x using sha256) from y;
|
||||
|
||||
|
||||
----
|
||||
|
@ -1714,6 +1714,8 @@ C --
|
||||
PARAMETER (GDS__subfunc_not_impl = 335545150)
|
||||
INTEGER*4 GDS__subproc_not_impl
|
||||
PARAMETER (GDS__subproc_not_impl = 335545151)
|
||||
INTEGER*4 GDS__sysf_invalid_hash_algorithm
|
||||
PARAMETER (GDS__sysf_invalid_hash_algorithm = 335545152)
|
||||
INTEGER*4 GDS__gfix_db_name
|
||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||
INTEGER*4 GDS__gfix_invalid_sw
|
||||
|
@ -1709,6 +1709,8 @@ const
|
||||
gds_subfunc_not_impl = 335545150;
|
||||
isc_subproc_not_impl = 335545151;
|
||||
gds_subproc_not_impl = 335545151;
|
||||
isc_sysf_invalid_hash_algorithm = 335545152;
|
||||
gds_sysf_invalid_hash_algorithm = 335545152;
|
||||
isc_gfix_db_name = 335740929;
|
||||
gds_gfix_db_name = 335740929;
|
||||
isc_gfix_invalid_sw = 335740930;
|
||||
|
@ -7709,7 +7709,6 @@ system_function_std_syntax
|
||||
| EXP
|
||||
| FLOOR
|
||||
| GEN_UUID
|
||||
| HASH
|
||||
| LEFT
|
||||
| LN
|
||||
| LOG
|
||||
@ -7769,6 +7768,14 @@ system_function_special_syntax
|
||||
newNode<ValueListNode>(MAKE_const_slong($3))->add($5)->add($7));
|
||||
$$->dsqlSpecialSyntax = true;
|
||||
}
|
||||
| HASH '(' value ')'
|
||||
{ $$ = newNode<SysFuncCallNode>(*$1, newNode<ValueListNode>($3)); }
|
||||
| HASH '(' value USING valid_symbol_name ')'
|
||||
{
|
||||
$$ = newNode<SysFuncCallNode>(*$1,
|
||||
newNode<ValueListNode>($3)->add(MAKE_str_constant(newIntlString($5->c_str()), CS_ASCII)));
|
||||
$$->dsqlSpecialSyntax = true;
|
||||
}
|
||||
| OVERLAY '(' value PLACING value FROM value FOR value ')'
|
||||
{
|
||||
$$ = newNode<SysFuncCallNode>(*$1,
|
||||
|
@ -853,6 +853,7 @@ static const struct {
|
||||
{"subproc_defvaldecl", 335545149},
|
||||
{"subfunc_not_impl", 335545150},
|
||||
{"subproc_not_impl", 335545151},
|
||||
{"sysf_invalid_hash_algorithm", 335545152},
|
||||
{"gfix_db_name", 335740929},
|
||||
{"gfix_invalid_sw", 335740930},
|
||||
{"gfix_incmp_sw", 335740932},
|
||||
|
@ -887,6 +887,7 @@ const ISC_STATUS isc_subfunc_defvaldecl = 335545148L;
|
||||
const ISC_STATUS isc_subproc_defvaldecl = 335545149L;
|
||||
const ISC_STATUS isc_subfunc_not_impl = 335545150L;
|
||||
const ISC_STATUS isc_subproc_not_impl = 335545151L;
|
||||
const ISC_STATUS isc_sysf_invalid_hash_algorithm = 335545152L;
|
||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||
@ -1361,7 +1362,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||
const ISC_STATUS isc_err_max = 1305;
|
||||
const ISC_STATUS isc_err_max = 1306;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2218,6 +2219,7 @@ const ISC_STATUS isc_err_max = 1305;
|
||||
#define isc_subproc_defvaldecl 335545149L
|
||||
#define isc_subfunc_not_impl 335545150L
|
||||
#define isc_subproc_not_impl 335545151L
|
||||
#define isc_sysf_invalid_hash_algorithm 335545152L
|
||||
#define isc_gfix_db_name 335740929L
|
||||
#define isc_gfix_invalid_sw 335740930L
|
||||
#define isc_gfix_incmp_sw 335740932L
|
||||
@ -2692,7 +2694,7 @@ const ISC_STATUS isc_err_max = 1305;
|
||||
#define isc_trace_switch_param_miss 337182758L
|
||||
#define isc_trace_param_act_notcompat 337182759L
|
||||
#define isc_trace_mandatory_switch_miss 337182760L
|
||||
#define isc_err_max 1305
|
||||
#define isc_err_max 1306
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -856,6 +856,7 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545149, "Default values for parameters are not allowed in definition of the previously declared sub-procedure @1"}, /* subproc_defvaldecl */
|
||||
{335545150, "Sub-function @1 was declared but not implemented"}, /* subfunc_not_impl */
|
||||
{335545151, "Sub-procedure @1 was declared but not implemented"}, /* subproc_not_impl */
|
||||
{335545152, "Invalid HASH algorithm @1"}, /* sysf_invalid_hash_algorithm */
|
||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||
|
@ -852,6 +852,7 @@ static const struct {
|
||||
{335545149, -901}, /* 829 subproc_defvaldecl */
|
||||
{335545150, -901}, /* 830 subfunc_not_impl */
|
||||
{335545151, -901}, /* 831 subproc_not_impl */
|
||||
{335545152, -901}, /* 832 sysf_invalid_hash_algorithm */
|
||||
{335740929, -901}, /* 1 gfix_db_name */
|
||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||
|
@ -852,6 +852,7 @@ static const struct {
|
||||
{335545149, "42000"}, // 829 subproc_defvaldecl
|
||||
{335545150, "42000"}, // 830 subfunc_not_impl
|
||||
{335545151, "42000"}, // 831 subproc_not_impl
|
||||
{335545152, "42000"}, // 832 sysf_invalid_hash_algorithm
|
||||
{335740929, "00000"}, // 1 gfix_db_name
|
||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "../jrd/trace/TraceObjects.h"
|
||||
#include "../jrd/Collation.h"
|
||||
#include "../common/classes/FpeControl.h"
|
||||
#include <functional>
|
||||
#include <math.h>
|
||||
|
||||
using namespace Firebird;
|
||||
@ -101,6 +102,37 @@ enum TrigonFunction
|
||||
};
|
||||
|
||||
|
||||
struct HashAlgorithmDescriptor
|
||||
{
|
||||
const char* name;
|
||||
USHORT length;
|
||||
std::function<HashContext* (MemoryPool&)> create;
|
||||
|
||||
static const HashAlgorithmDescriptor* find(const char* name);
|
||||
};
|
||||
|
||||
static const HashAlgorithmDescriptor hashAlgorithmDescriptors[] = {
|
||||
{"MD5", 16, [](MemoryPool& pool) { return FB_NEW_POOL(pool) Md5HashContext(pool); }},
|
||||
{"SHA1", 20, [](MemoryPool& pool) { return FB_NEW_POOL(pool) Sha1HashContext(pool); }},
|
||||
{"SHA256", 32, [](MemoryPool& pool) { return FB_NEW_POOL(pool) Sha256HashContext(pool); }},
|
||||
{"SHA512", 64, [](MemoryPool& pool) { return FB_NEW_POOL(pool) Sha512HashContext(pool); }}
|
||||
};
|
||||
|
||||
const HashAlgorithmDescriptor* HashAlgorithmDescriptor::find(const char* name)
|
||||
{
|
||||
unsigned count = FB_NELEM(hashAlgorithmDescriptors);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
if (strcmp(name, hashAlgorithmDescriptors[i].name) == 0)
|
||||
return &hashAlgorithmDescriptors[i];
|
||||
}
|
||||
|
||||
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// constants
|
||||
const int oneDay = 86400;
|
||||
|
||||
@ -145,6 +177,7 @@ void makeBinShift(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, d
|
||||
void makeCeilFloor(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeDateAdd(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeHash(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeLeftRight(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeMod(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
void makeOverlay(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args);
|
||||
@ -901,6 +934,27 @@ void makeGetSetContext(DataTypeUtilBase* /*dataTypeUtil*/, const SysFunction* fu
|
||||
}
|
||||
|
||||
|
||||
void makeHash(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result,
|
||||
int argsCount, const dsc** args)
|
||||
{
|
||||
fb_assert(argsCount >= function->minArgCount);
|
||||
|
||||
if (argsCount == 1)
|
||||
makeInt64Result(dataTypeUtil, function, result, argsCount, args);
|
||||
else if (argsCount >= 2)
|
||||
{
|
||||
if (!args[1]->dsc_address || !args[1]->isText()) // not a constant
|
||||
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << "<not a string constant>");
|
||||
|
||||
MetaName algorithmName;
|
||||
MOV_get_metaname(JRD_get_thread_data(), args[1], algorithmName);
|
||||
|
||||
result->makeVarying(HashAlgorithmDescriptor::find(algorithmName.c_str())->length, ttype_binary);
|
||||
result->setNullable(args[0]->isNullable());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void makeLeftRight(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result,
|
||||
int argsCount, const dsc** args)
|
||||
{
|
||||
@ -2640,7 +2694,7 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
|
||||
dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
|
||||
impure_value* impure)
|
||||
{
|
||||
fb_assert(args.getCount() == 1);
|
||||
fb_assert(args.getCount() >= 1);
|
||||
|
||||
jrd_req* request = tdbb->getRequest();
|
||||
|
||||
@ -2648,8 +2702,27 @@ 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;
|
||||
AutoPtr<HashContext> hashContext;
|
||||
MemoryPool& pool = *request->req_pool;
|
||||
|
||||
if (args.getCount() >= 2)
|
||||
{
|
||||
const dsc* algorithmDesc = EVL_expr(tdbb, request, args[1]);
|
||||
if (request->req_flags & req_null) // return NULL if algorithm is NULL
|
||||
return NULL;
|
||||
|
||||
if (!algorithmDesc->isText())
|
||||
status_exception::raise(Arg::Gds(isc_sysf_invalid_hash_algorithm) << "<not a string constant>");
|
||||
|
||||
MetaName algorithmName;
|
||||
MOV_get_metaname(tdbb, algorithmDesc, algorithmName);
|
||||
hashContext.reset(HashAlgorithmDescriptor::find(algorithmName.c_str())->create(pool));
|
||||
}
|
||||
else
|
||||
{
|
||||
hashContext.reset(FB_NEW_POOL(pool) WeakHashContext());
|
||||
impure->vlu_misc.vlu_int64 = 0;
|
||||
}
|
||||
|
||||
if (value->isBlob())
|
||||
{
|
||||
@ -2660,7 +2733,7 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
|
||||
while (!(blob->blb_flags & BLB_eof))
|
||||
{
|
||||
const ULONG length = blob->BLB_get_data(tdbb, buffer, sizeof(buffer), false);
|
||||
hashContext.update(buffer, length);
|
||||
hashContext->update(buffer, length);
|
||||
}
|
||||
|
||||
blob->BLB_close(tdbb);
|
||||
@ -2670,17 +2743,26 @@ dsc* evlHash(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
|
||||
UCHAR* address;
|
||||
MoveBuffer buffer;
|
||||
const ULONG length = MOV_make_string2(tdbb, value, value->getTextType(), &address, buffer, false);
|
||||
hashContext.update(address, length);
|
||||
hashContext->update(address, length);
|
||||
}
|
||||
|
||||
HashContext::Buffer resultBuffer;
|
||||
hashContext.finish(resultBuffer);
|
||||
hashContext->finish(resultBuffer);
|
||||
|
||||
fb_assert(resultBuffer.getCount() == sizeof(SINT64));
|
||||
memcpy(&impure->vlu_misc.vlu_int64, resultBuffer.begin(), sizeof(SINT64));
|
||||
if (args.getCount() >= 2)
|
||||
{
|
||||
dsc result;
|
||||
result.makeText(resultBuffer.getCount(), ttype_binary, resultBuffer.begin());
|
||||
EVL_make_value(tdbb, &result, impure);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
// make descriptor for return value
|
||||
impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64);
|
||||
}
|
||||
|
||||
return &impure->vlu_desc;
|
||||
}
|
||||
@ -4262,7 +4344,7 @@ const SysFunction SysFunction::functions[] =
|
||||
{"EXP", 1, 1, setParamsDblDec, makeDblDecResult, evlExp, NULL},
|
||||
{"FLOOR", 1, 1, setParamsDblDec, makeCeilFloor, evlFloor, NULL},
|
||||
{"GEN_UUID", 0, 0, NULL, makeUuid, evlGenUuid, NULL},
|
||||
{"HASH", 1, 1, NULL, makeInt64Result, evlHash, NULL},
|
||||
{"HASH", 1, 2, NULL, makeHash, evlHash, NULL},
|
||||
{"LEFT", 2, 2, setParamsSecondInteger, makeLeftRight, evlLeft, NULL},
|
||||
{"LN", 1, 1, setParamsDblDec, makeDblDecResult, evlLnLog10, (void*) funLnat},
|
||||
{"LOG", 2, 2, setParamsDblDec, makeDblDecResult, evlLog, NULL},
|
||||
|
@ -176,7 +176,7 @@ void MOV_get_metaname(Jrd::thread_db* tdbb, const dsc* desc, MetaName& name)
|
||||
|
||||
fb_assert(length && ptr);
|
||||
fb_assert(length <= MAX_SQL_IDENTIFIER_LEN);
|
||||
fb_assert(ttype == ttype_metadata);
|
||||
fb_assert(ttype == ttype_ascii || ttype == ttype_metadata);
|
||||
|
||||
name.assign(reinterpret_cast<char*>(ptr), length);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||
--
|
||||
('2017-07-10 12:27:00', 'JRD', 0, 832)
|
||||
('2017-07-24 12:10:00', 'JRD', 0, 833)
|
||||
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||
|
@ -939,6 +939,7 @@ Data source : @4', NULL, NULL)
|
||||
('subproc_defvaldecl', NULL, 'StmtNodes.cpp', NULL, 0, 829, NULL, 'Default values for parameters are not allowed in definition of the previously declared sub-procedure @1', NULL, NULL);
|
||||
('subfunc_not_impl', NULL, 'StmtNodes.cpp', NULL, 0, 830, NULL, 'Sub-function @1 was declared but not implemented', NULL, NULL);
|
||||
('subproc_not_impl', NULL, 'StmtNodes.cpp', NULL, 0, 831, NULL, 'Sub-procedure @1 was declared but not implemented', NULL, NULL);
|
||||
('sysf_invalid_hash_algorithm', NULL, 'SysFunction.cpp', NULL, 0, 832, NULL, 'Invalid HASH algorithm @1', NULL, NULL);
|
||||
-- QLI
|
||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||
|
@ -838,6 +838,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-901, '42', '000', 0, 829, 'subproc_defvaldecl', NULL, NULL)
|
||||
(-901, '42', '000', 0, 830, 'subfunc_not_impl', NULL, NULL)
|
||||
(-901, '42', '000', 0, 831, 'subproc_not_impl', NULL, NULL)
|
||||
(-901, '42', '000', 0, 832, 'sysf_invalid_hash_algorithm', NULL, NULL)
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user