Nun, wenn es "zu verwenden scheint", dann ist es sinnvoll, ein wenig Reverse Engineering durchzuführen und zu überprüfen, was genau aufgerufen wird, und den Code der Funktion zu zerlegen.
Wenn Sie jedoch in die Interna von Oracle eintauchen möchten, kann Folgendes hilfreich sein.
Zunächst einmal müssen Sie herausfinden, welche interne C-Funktion aufgerufen wird. Dazu können Sie langlaufenden Code in einer Sitzung ausführen. Ich habe dies ausgeführt
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Es kann auch PL/SQL-Code sein, Sie müssen nur sicherstellen, dass Sie ständig ora_hash aufrufen.
Während es läuft
-
Unter Windows können Sie ostackprof von TANEL PODER (https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-ostackprof/ )
-
Wenn Sie auf *nix sind, können Sie dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (Nutzungsszenario https://blog.dbi -services.com/oracle-database-multilingual-engine-ml/ )
Ich habe es unter Windows getestet und es sieht so aus, als ob ora_hash ...->evaopn2()->evahash() ist ->...
Lassen Sie uns jetzt nach evahash googeln. Wir hatten großes Glück, denn es gibt eine Header-Datei auf der offiziellen Seite https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h mit Link zu evahash.
Und schließlich gibt es eine Seite mit aktuellem C-Code http://burtleburtle.net/bob/hash/ evahash.html
Soweit so gut, wir erinnern uns, dass wir externe C-Funktionen in Oracle verwenden können, wenn wir sie in die Bibliothek (DLL unter Windows) einbauen.
Zum Beispiel auf meinem Win x64, wenn ich die Funktionssignatur in
ändereextern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
Es kann erfolgreich von Oracle ausgeführt werden. Aber wie Sie sehen, unterscheidet sich die Signatur ein wenig von ora_hash in Oracle. Diese Funktion akzeptiert Wert, ihre Länge und Initialisierung (kann Seed sein), während die Signatur in Oracle ora_hash(expr, max_bucket, seed_value) ist.
Lassen Sie uns versuchen, Oracle zu testen
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
Keine der Zahlen stimmt überein. Was ist also das Problem? ora_hash akzeptiert Parameter fast jeden Typs (zum Beispiel select ora_hash(sys.odcinumberlist(1,2,3)) from dual
), während die C-Funktion den Wert als Array von Bytes akzeptiert. Dies bedeutet, dass vor dem Funktionsaufruf eine gewisse Konvertierung stattfindet. Bevor Sie die erwähnte C-Hash-Funktion verwenden, müssen Sie also herausfinden, wie der tatsächliche Wert umgewandelt wird, bevor er an ihn übergeben wird.
Sie können mit dem Reverse Engineering von Oracle-Binärdateien mit IDA PRO + Hex-Rays fortfahren, aber das kann Tage dauern. Ganz zu schweigen von plattformspezifischen Details.
Wenn Sie also ora_hash imitieren möchten, wäre die einfachste Option, die Oracle Express Edition zu installieren und sie zum Aufrufen von ora_hash zu verwenden.
Ich hoffe, das war interessant. Viel Glück.
Aktualisieren
ora_hash und dbms_utility.get_hash_value können aufeinander abgebildet werden (siehe 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
Wenn wir den Paketkörper von dbms_utility auspacken, sehen wir die folgende Deklaration
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
und
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Lassen Sie uns nach icd_hash
googeln und wir können feststellen, dass es _psdhsh
zugeordnet ist (https://yurichev.com/blog/50/
). Jetzt ist es an der Zeit, oracle.exe zu disassemblieren und den Code für _psdhsh
zu extrahieren davon. Vielleicht verbringe ich nächstes Jahr etwas Zeit damit.