Welnu, als het "lijkt te gebruiken", dan is het logisch om een beetje reverse-engineering uit te voeren en te controleren wat er precies wordt aangeroepen en de code van de functie te demonteren.
Als u zich echter in Oracle internals wilt verdiepen, kan het volgende helpen.
Allereerst moet je uitzoeken hoe de interne C-functie wordt genoemd. Om dat te doen, kun je een langlopende code in één sessie uitvoeren. Ik heb dit uitgevoerd
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Het kan ook PL/SQL-code zijn, je moet er alleen voor zorgen dat je constant ora_hash aanroept.
Terwijl het draait
-
Als u Windows gebruikt, kunt u ostackprof van TANEL PODER gebruiken(https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profilering-van-sqlplus-gebruiken-ostapelprof/ )
-
Als u *nix gebruikt, kunt u dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (gebruiksscenario https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Ik heb getest op Windows en het lijkt erop dat ora_hash is ...->evaopn2()->evahash() ->...
Laten we nu googlen op evahash. We hebben enorm veel geluk gehad, want er is een header-bestand op de officiële site https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h met link naar evahash.
En tot slot is er een pagina met daadwerkelijke C-code http://burtleburtle.net/bob/hash/ evahash.html
Tot nu toe zo goed, we herinneren ons dat we de externe C-functie in Oracle kunnen gebruiken als we deze in de bibliotheek (DLL op Windows) bouwen.
Bijvoorbeeld op mijn Win x64 als ik de functiehandtekening verander in
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
het kan met succes worden uitgevoerd vanuit Oracle. Maar zoals je ziet, verschilt de handtekening een beetje van ora_hash in Oracle. Deze functie accepteert waarde, lengte en beginwaarde (kan seed zijn), terwijl de handtekening in Oracle ora_hash(expr, max_bucket, seed_value) is.
Laten we proberenOracle . te 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
Geen van de nummers komt overeen. Dus wat is het probleem?ora_hash accepteert parameters van bijna elk type (bijvoorbeeld select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) terwijl de C-functie waarde accepteert als array van bytes. Dit betekent dat er enige conversie plaatsvindt voordat de functie wordt aangeroepen. Voordat u de genoemde C-hash-functie gebruikt, moet u dus uitzoeken hoe de werkelijke waarde wordt getransformeerd voordat u ernaartoe gaat.
U kunt doorgaan met reverse-engineering van Oracle-binaire bestanden met behulp van IDA PRO + hex-stralen, maar dat kan dagen duren. Om nog maar te zwijgen over platformspecifieke details.
Dus als u ora_hash wilt imiteren, is de eenvoudigste optie om Oracle Express Edition te installeren en deze te gebruiken om ora_hash aan te roepen.
Ik hoop dat het interessant was. Veel succes.
Bijwerken
ora_hash en dbms_utility.get_hash_value kunnen aan elkaar worden toegewezen (zie 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
Als we de pakkettekst van dbms_utility uitpakken, zien we de volgende verklaring
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
en
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Laten we googlen voor icd_hash
en we kunnen zien dat het is toegewezen aan _psdhsh
(https://yurichev.com/blog/50/
). Nu is het tijd om oracle.exe te demonteren en de code voor _psdhsh
te extraheren ervan. Misschien zal ik hier volgend jaar wat tijd aan besteden.