No, pokud se "zdá, že se používá", pak má smysl udělat trochu reverzního inženýrství a zkontrolovat, co přesně se nazývá, a rozebrat kód funkce.
Pokud se však chcete ponořit do interních informací Oracle, může vám pomoci následující.
Nejprve musíte zjistit, jak se nazývá interní funkce C. Chcete-li to provést, můžete během jedné relace spustit nějaký dlouhý kód. Spustil jsem toto
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Může to být i kód PL/SQL, jen se musíte ujistit, že neustále voláte ora_hash.
Zatímco běží
-
Pokud používáte Windows, můžete použít ostackprof od TANEL PODER (https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-ostackprof/ )
-
Pokud používáte *nix, můžete použít dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (scénář použití https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Testoval jsem na Windows a vypadá to, že ora_hash je ...->evaopn2()->evahash() ->...
Teď pojďme googlovat evashash. Měli jsme obrovské štěstí, protože na oficiálních stránkách je soubor záhlaví https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h s odkazem na evashash.
A nakonec je tu stránka se skutečným C kódem http://burtleburtle.net/bob/hash/ evashash.html
Zatím dobře, pamatujeme si, že můžeme použít externí C funkci v Oracle, pokud ji zabudujeme do knihovny (DLL ve Windows).
Například na mém Win x64, pokud změním podpis funkce na
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
lze jej úspěšně spustit z Oracle. Ale jak vidíte, podpis se trochu liší od ora_hash v Oracle. Tato funkce přijímá hodnotu, její délku a initval (může být seed), zatímco podpis v Oracle je ora_hash(expr, max_bucket, seed_value).
Zkusme otestovatOracle
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 4056412421
C
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
Žádné z čísel se neshoduje. V čem je tedy problém?ora_hash přijímá parametry téměř jakéhokoli typu (například select ora_hash(sys.odcinumberlist(1,2,3)) from dual
), zatímco funkce C přijímá hodnotu jako pole bajtů. To znamená, že před voláním funkce dojde k určité konverzi. Před použitím zmíněné hašovací funkce C tedy musíte zjistit, jak se skutečná hodnota transformuje, než jí předáte.
Můžete pokračovat v reverzním inženýrství binárních souborů Oracle pomocí IDA PRO + hex rays, ale to může trvat dny. Nemluvě o podrobnostech specifických pro platformu.
Pokud tedy chcete napodobit ora_hash, nejjednodušší možností by bylo nainstalovat Oracle express edition a použít ji k volání ora_hash.
Doufám, že to bylo zajímavé. Hodně štěstí.
Aktualizovat
ora_hash a dbms_utility.get_hash_value lze vzájemně mapovat (viz https:/ /jonathanlewis.wordpress.com/2009/11/21/ora_hash-function/ )
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
Pokud rozbalíme tělo balíčku dbms_utility, uvidíme následující deklaraci
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
a
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Vyhledejme icd_hash
a můžeme zjistit, že je namapován na _psdhsh
(https://yurichev.com/blog/50/
). Nyní je čas rozebrat oracle.exe a extrahovat kód pro _psdhsh
z toho. Možná tomu příští rok strávím nějaký čas.