Cóż, jeśli "wydaje się używać", warto zrobić trochę inżynierii wstecznej i sprawdzić, co dokładnie jest wywoływane, i zdeasemblować kod funkcji.
Jeśli jednak chcesz zagłębić się w wewnętrzne rozwiązania Oracle, pomocne może być poniższe postępowanie.
Przede wszystkim musisz dowiedzieć się, jaka wewnętrzna funkcja C jest wywoływana. Aby to zrobić, możesz wykonać jakiś długo działający kod w jednej sesji. Uruchomiłem to
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Może to być również kod PL/SQL, wystarczy upewnić się, że ciągle wywołujesz ora_hash.
Podczas działania
-
Jeśli korzystasz z systemu Windows, możesz użyć ostackprof autorstwa TANEL PODER(https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-stackprof/ )
-
Jeśli korzystasz z *nix, możesz użyć dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Wykres płomienia (scenariusz użycia https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Testowałem na Windowsie i wygląda na to, że ora_hash to ...->evaopn2()->evahash() ->...
Teraz wyszukajmy evahash. Mieliśmy ogromne szczęście, ponieważ na oficjalnej stronie znajduje się plik nagłówkowy https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h z linkiem do evahash.
I wreszcie strona z aktualnym kodem C http://burtleburtle.net/bob/hash/ evahash.html
Jak dotąd dobrze pamiętamy, że możemy użyć zewnętrznej funkcji C w Oracle, jeśli wbudujemy ją w bibliotekę (DLL na Windows).
Na przykład na moim Win x64, jeśli zmienię sygnaturę funkcji na
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
można go z powodzeniem wykonać z Oracle. Ale, jak widać, sygnatura nieco różni się od ora_hash w Oracle. Funkcja ta przyjmuje wartość, jej długość i initval (może być seedem), podczas gdy sygnatura w Oracle to ora_hash(expr, max_bucket, seed_value).
Spróbujmy przetestowaćOracle
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
Żadna z liczb nie pasuje. Więc w czym problem? ora_hash akceptuje parametry prawie każdego typu (na przykład select ora_hash(sys.odcinumberlist(1,2,3)) from dual
), podczas gdy funkcja C przyjmuje wartość jako tablicę bajtów. Oznacza to, że pewna konwersja ma miejsce przed wywołaniem funkcji. Dlatego przed użyciem wspomnianej funkcji skrótu C musisz dowiedzieć się, jak rzeczywista wartość jest przekształcana przed przekazaniem do niej.
Możesz kontynuować inżynierię odwrotną plików binarnych Oracle za pomocą IDA PRO + promieni szesnastkowych, ale może to potrwać kilka dni. Nie wspominając o szczegółach dotyczących platformy.
Jeśli więc chcesz naśladować ora_hash, najłatwiejszą opcją byłoby zainstalowanie wersji Oracle express i użycie jej do wywołania ora_hash.
Mam nadzieję, że to było interesujące. Powodzenia.
Aktualizacja
ora_hash i dbms_utility.get_hash_value mogą być ze sobą mapowane (patrz 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
Jeśli rozpakujemy ciało pakietu dbms_utility, zobaczymy następującą deklarację
Funkcja function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
i
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Poszukajmy w Google icd_hash
i możemy stwierdzić, że jest zmapowany do _psdhsh
(https://yurichev.com/blog/50/
). Teraz nadszedł czas na deasemblację oracle.exe i wyodrębnienie kodu dla _psdhsh
z tego. Może spędzę nad tym trochę czasu w przyszłym roku.