在我正在开发的应用程序中,我遇到了一些代码,这些代码使数据库调用仅仅是为了调用UUID字符串上的ORA_HASH函数(文档)。之所以这样做,是因为它需要对另一个似乎使用ORA_HASH进行分区的系统进行服务调用。
我想知道ORA_HASH使用的算法,这样我就可以重新实现它,以便对无法访问真正数据库的应用程序进行类似的服务调用,更不用说Oracle了。到目前为止,我只找到了相当于Oracle API文档的内容。
非常清楚:,我需要克隆ORA_HASH,因为这是我无法控制的另一个系统所使用的,我需要与该系统集成。是的,如果能使用一个真正标准的算法,比如MD5,那就太好了,但是我做不到,除非这就是ORA_HASH所隐藏的。
除了ORA_HASH之外,建议使用哈希算法的答案或评论是没有帮助的。这个问题是关于ORA_HASH的,而不是一般的散列或分区。
发布于 2017-12-17 13:33:59
另一个似乎使用ORA_HASH的系统
嗯,如果它“似乎使用”,那么做一些反向工程和检查什么是确切的调用和反汇编的函数代码是有意义的。
但是,如果您想深入研究Oracle的内部结构,那么下面的内容可能会有所帮助。
首先,您必须弄清楚调用什么内部C函数。要做到这一点,您可以在一个会话中执行一些长期运行的代码。我确实做了这个
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);它也可以是PL/SQL代码,您只需确保不断调用ora_hash即可。
当它在运行时
我在Windows上进行了测试,看起来ora_hash是ora_hash
现在让我们用谷歌搜索evahash。我们非常幸运,因为官方网站https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h上有一个头文件,链接到evahash。
最后是带有实际C代码http://burtleburtle.net/bob/hash/evahash.html的页面
到目前为止,我们还记得,如果我们将外部C函数构建到库(Windows上的DLL)中,就可以在Oracle中使用它。
例如,如果我将函数签名更改为
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)它可以从Oracle成功地执行。但是,正如您所看到的,签名与甲骨文中的ora_hash稍有不同。此函数接受值、其长度和initval (可能是种子),而在Oracle中的签名是ora_hash(expr、max_bucket、seed_value)。
让我们试着测试甲骨文
SQL> select ora_hash(utl_raw.cast_to_raw('0'), power(2, 32) - 1, 0) oh1,
2 ora_hash('0', power(2, 32) - 1, 0) oh2,
3 ora_hash(0, power(2, 32) - 1, 0) oh3,
4 ora_hash(chr(0), power(2, 32) - 1, 0) oh4
5 from dual;
OH1 OH2 OH3 OH4
---------- ---------- ---------- ----------
3517341953 3517341953 1475158189 4056412421C
int main()
{
ub1 ta[] = {0};
ub1* t = ta;
cout << hash(t, 1, 0) << endl;
ub1 ta0[] = {'0'};
ub1* t0 = ta0;
cout << hash(t0, 1, 0) << endl;
return 0;
}
1843378377
4052366646所有的数字都不符合。那么问题是什么呢?ora_hash接受几乎任何类型的参数(例如,select ora_hash(sys.odcinumberlist(1,2,3)) from dual),而C函数接受值作为字节数组。这意味着在函数调用之前会发生一些转换。因此,在使用上述C哈希函数之前,您必须先了解实际值在传递给它之前是如何转换的。
您可以使用IDA PRO +十六进制射线进行Oracle二进制文件的反向工程,但这可能需要几天时间。更不用说平台的具体细节了。
因此,如果您想模仿ora_hash,最简单的选择是安装Oracle版本并使用它调用ora_hash。
我希望那是有趣的。祝好运。
更新
ora_hash和dbms_utility.get_hash_value可以相互映射(参见散列函数/)
SQL> select dbms_utility.get_hash_value('0', 0 + 1, 1e6 + 1) ha1,
2 ora_hash('0', 1e6, 0) + 1 ha2
3 from dual;
HA1 HA2
---------- ----------
338437 338437如果我们打开dbms_utility的包体,我们将看到以下声明
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;和
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);让我们为icd_hash谷歌,我们可以发现它被映射到_psdhsh (https://yurichev.com/blog/50/)。现在是时候拆解oracle.exe并从其中提取_psdhsh的代码了。也许明年我会花点时间在这个问题上。
发布于 2017-12-14 19:03:51
这并没有回答ora_hash后面的实际algo这个OP问题。这只是在pl/sql中使用ora_hash的一个例子(应答@JonHeller注释):
职能:
SQL> create or replace function get_ora_hash(i_str in varchar2, i_max_bucket in number default 4294967295, i_seed number default 0)
return number deterministic
parallel_enable
as
rv number:= 0;
begin
select ORA_HASH(i_str, i_max_bucket, i_seed)
into rv
from dual;
return rv;
end;
Function created.并使用它:
SQL> declare
l_val number;
begin
l_val := get_ora_hash('test');
dbms_output.put_line(l_val);
end;
PL/SQL procedure successfully completed.Dbms输出:
2662839991您还可以使用RESULT_CACHE或其他技术来加快速度。
已经很快了。例如,在大型表上调用函数100万次:
SQL> set serveroutput on
SQL> declare
l_val number;
l_start_dte timestamp;
l_end_dte timestamp;
l_interval INTERVAL DAY(9) TO SECOND(9);
l_cnt number := 0;
begin
l_start_dte:= systimestamp;
--for rec in (select object_name from dba_objects)
for rec in (select name from my_big_table where rownum <= 1000000)
loop
l_cnt := l_cnt + 1;
l_val := get_ora_hash(rec.name);
end loop;
l_end_dte:= systimestamp;
l_interval := l_end_dte - l_start_dte;
dbms_output.put_line('Rows processed: ' || l_cnt
|| ', Start: ' || l_start_dte
|| ', End: ' || l_end_dte
|| ', Interval: ' || l_interval);
end;
Rows processed: 1000000, Start: 14-DEC-17 02.48.31.138212 PM, End: 14-DEC-17 02.48.41.148884 PM, Interval: +000000000 00:00:10.010672000
PL/SQL procedure successfully completed.基本上是每秒100行,包括你可能担心的任何上下文开关。
如果由于性能原因需要复制ORA_HASH,我建议您的性能瓶颈可能在其他地方。
https://stackoverflow.com/questions/45948266
复制相似问题