Bene, se "sembra usare", allora ha senso fare un po' di reverse engineering e controllare cosa si chiama esattamente e smontare il codice della funzione.
Se, tuttavia, desideri approfondire gli aspetti interni di Oracle, seguire la procedura potrebbe essere d'aiuto.
Prima di tutto, devi capire quale funzione C interna viene chiamata. Per farlo puoi eseguire del codice di lunga durata in una sessione. L'ho eseguito
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Può essere anche codice PL/SQL, devi solo assicurarti di chiamare costantemente ora_hash.
Mentre è in esecuzione
-
Se utilizzi Windows, puoi utilizzare ostackprof di TANEL PODER(https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-ostackprof/ )
-
Se sei su *nix, puoi usare dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (scenario di utilizzo https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Ho provato su Windows e sembra che ora_hash sia ...->evaopn2()->evahash() ->...
Ora cerchiamo su Google evahash. Siamo stati estremamente fortunati perché c'è un file di intestazione sul sito ufficiale https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h con link a evahash.
E infine c'è una pagina con il codice C effettivo http://burtleburtle.net/bob/hash/ evahash.html
Fin qui tutto bene, ricordiamo che possiamo usare la funzione C esterna in Oracle se la incorporiamo nella libreria (DLL su Windows).
Ad esempio sul mio Win x64 se cambio la firma della funzione in
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
può essere eseguito con successo da Oracle. Ma, come vedi, la firma differisce leggermente da ora_hash in Oracle. Questa funzione accetta il valore, la sua lunghezza e initval (può essere seed) mentre la firma in Oracle è ora_hash(expr, max_bucket, seed_value).
Proviamo a testareOracle
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
Nessuno dei numeri corrisponde. Allora qual è il problema?ora_hash accetta parametri di quasi tutti i tipi (ad esempio select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) mentre la funzione C accetta il valore come matrice di byte. Ciò significa che alcune conversioni avvengono prima della chiamata della funzione. Quindi, prima di utilizzare la funzione hash C menzionata, devi capire come viene trasformato il valore effettivo prima di passarlo.
Puoi procedere con il reverse engineering dei binari Oracle utilizzando IDA PRO + raggi esadecimali, ma ciò potrebbe richiedere giorni. Per non parlare dei dettagli specifici della piattaforma.
Quindi, se vuoi imitare ora_hash, l'opzione più semplice sarebbe installare Oracle Express Edition e usarla per chiamare ora_hash.
Spero sia stato interessante. Buona fortuna.
Aggiorna
ora_hash e dbms_utility.get_hash_value possono essere mappati tra loro (vedi 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
Se scartiamo il corpo del pacchetto di dbms_utility vedremo la seguente dichiarazione
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
e
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Cerchiamo su Google icd_hash
e possiamo scoprire che è mappato su _psdhsh
(https://yurichev.com/blog/50/
). Ora è il momento di disassemblare oracle.exe ed estrarre il codice per _psdhsh
da. Forse ci dedicherò un po' di tempo l'anno prossimo.