Tja, om det "tycks användas" så är det vettigt att göra lite reverse engineering och kolla vad exakt heter och ta isär koden för funktionen.
Om du däremot vill dyka in i Oracles interna funktioner kan följande hjälpa.
Först och främst måste du ta reda på vad den interna C-funktionen kallas. För att göra det kan du köra lite långvarig kod i en session. Jag körde den här
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Det kan vara PL/SQL-kod också, du behöver bara se till att du ständigt ringer ora_hash.
Medan den är igång
-
Om du använder Windows kan du använda ostackprof av TANEL PODER(https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-ostackprof/ )
-
Om du är på *nix kan du använda dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (användningsscenario https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Jag testade på Windows och ser ut som att ora_hash är ...->evaopn2()->evahash() ->...
Låt oss nu googla efter evahash. Vi hade extremt tur eftersom det finns en rubrikfil på den officiella webbplatsen https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h med länk till evahash.
Och slutligen finns det en sida med faktisk C-kod http://burtleburtle.net/bob/hash/ evahash.html
Så långt har det gått bra, vi kommer ihåg att vi kan använda extern C-funktion i Oracle om vi bygger in den i biblioteket (DLL på Windows).
Till exempel på min Win x64 om jag ändrar funktionssignatur till
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
den kan köras framgångsrikt från Oracle. Men som du ser skiljer sig signaturen lite från ora_hash i Oracle. Denna funktion accepterar värde, dess längd och initval (kan vara seed) medan signaturen i Oracle är ora_hash(expr, max_bucket, seed_value).
Låt oss försöka testaOracle
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
Inget av siffrorna matchar. Så vad är problemet?ora_hash accepterar parametrar av nästan vilken typ som helst (till exempel select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) medan C-funktionen accepterar värde som array av byte. Detta innebär att viss konvertering sker före funktionsanrop. Innan du använder nämnda C-hash-funktion måste du alltså ta reda på hur det faktiska värdet omvandlas innan du går vidare till det.
Du kan fortsätta med omvänd konstruktion av Oracle-binärfiler med IDA PRO + hex-strålar men det kan ta dagar. För att inte tala om plattformsspecifika detaljer.
Så om du vill imitera ora_hash skulle det enklaste alternativet vara att installera Oracle Express edition och använda den för att anropa ora_hash.
Jag hoppas att det var intressant. Lycka till.
Uppdatera
ora_hash och dbms_utility.get_hash_value kan mappas till varandra (se 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
Om vi packar upp paketets innehåll av dbms_utility kommer vi att se följande deklaration
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
och
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Låt oss googla efter icd_hash
och vi kan se att den är mappad till _psdhsh
(https://yurichev.com/blog/50/
). Nu är det dags att plocka isär oracle.exe och extrahera kod för _psdhsh
från det. Jag kanske lägger lite tid på detta nästa år.