Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jaki algorytm wykorzystuje funkcja ORA_HASH?

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

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wybierz wiersze, gdy wartość kolumny zmieni się między datą w Oracle?

  2. Jak używać SYS_REFCURSUR w select do aktualizacji w pl/sql?

  3. Unikalne ograniczenie Oracle i unikalny indeks

  4. Błąd SQL - wyzwalacz/funkcja może go nie widzieć

  5. Nie można otworzyć lib '/usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1 podczas tworzenia elementu Database Monitor w zabbix