sql >> Database teknologi >  >> RDS >> Oracle

Hvad er den algoritme, der bruges af ORA_HASH-funktionen?

Tja, hvis det "ser ud til at bruge", så giver det mening at lave lidt omvendt konstruktion og tjekke, hvad der præcist hedder, og adskille koden for funktionen.

Hvis du derimod ønsker at dykke ned i Oracle internals, kan følgende hjælpe.

Først og fremmest skal du finde ud af, hvad den interne C-funktion kaldes. For at gøre det kan du udføre en lang kørende kode i én session. Jeg kørte denne

vælg avg(ora_hash(rownum)) id fra(vælg rækkenumre fra dual connect by rownum <=1e4),(vælg rownum fra dual connect by rownum <=1e4); 

Det kan også være PL/SQL-kode, du skal bare sørge for, at du konstant ringer til ora_hash.

Mens den kører

Jeg testede på Windows og ser ud som om, at ora_hash er ...->evaopn2()->evahash() ->...

Lad os nu google efter evahash. Vi var ekstremt heldige, fordi der er en header-fil på det officielle websted https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h med link til evahash.

Og endelig er der en side med den faktiske C-kode http://burtleburtle.net/bob/hash/ evahash.html

Så langt så godt, vi husker, at vi kan bruge ekstern C-funktion i Oracle, hvis vi indbygger det i biblioteket (DLL på Windows).

For eksempel på min Win x64, hvis jeg ændrer funktionssignatur til

ekstern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval) 

det kan udføres med succes fra Oracle. Men som du kan se, adskiller signaturen sig en smule fra ora_hash i Oracle. Denne funktion accepterer værdi, dens længde og initval (kan være seed), mens signatur i Oracle er ora_hash(expr, max_bucket, seed_value).

Lad os prøve at testeOracle

SQL> vælg 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 fra dual; OH1 OH2 OH3 OH4---------- ---------- ---------- ----------3517341953 3517341953 1475158189 4056412421 

C

int main(){ ub1 ta[] ={0}; ub1* t =ta; cout < 

Ingen af ​​tallene matcher. Så hvad er problemet?ora_hash accepterer parametre af næsten enhver type (for eksempel vælg ora_hash(sys.odcinumberlist(1,2,3)) fra dual ) mens C-funktionen accepterer værdi som en række bytes. Det betyder, at en vis konvertering sker før funktionskald. Før du bruger den nævnte C-hash-funktion, skal du altså finde ud af, hvordan den faktiske værdi transformeres, før du går videre til den.

Du kan fortsætte med reverse engineering af Oracle-binære filer ved hjælp af IDA PRO + hex-stråler, men det kan tage dage. For ikke at nævne platformspecifikke detaljer.

Så hvis du vil efterligne ora_hash, ville den nemmeste mulighed være at installere Oracle Express edition og bruge den til at kalde ora_hash.

Jeg håber, det var interessant. Held og lykke.

Opdater

ora_hash og dbms_utility.get_hash_value kan kortlægges til hinanden (se https:/ /jonathanlewis.wordpress.com/2009/11/21/ora_hash-function/ )

SQL> vælg dbms_utility.get_hash_value('0', 0 + 1, 1e6 + 1) ha1, 2 ora_hash('0', 1e6, 0) + 1 ha2 3 fra dual; HA1 HA2---------- ---------- 338437 338437 

Hvis vi udpakker pakketeksten af ​​dbms_utility, vil vi se følgende erklæring

funktion get_hash_value(navn varchar2, basisnummer, hash_size nummer) returnummer er start return(icd_hash(navn, base, hash_size)); ende;

og

funktion icd_hash(navn varchar2, basis binært_heltal, hash_størrelse binært_heltal) returner binært_heltal; pragma interface(c, icd_hash);

Lad os google efter icd_hash og vi kan finde ud af, at det er mappet til _psdhsh (https://yurichev.com/blog/50/ ). Nu er det tid til at skille oracle.exe ad og udtrække kode til _psdhsh fra det. Måske vil jeg bruge lidt tid på dette næste år.



  1. Soundex med tal som strengparameter

  2. N. maks. løn i Oracle

  3. SÅDAN vælger du min fra cast varchar til int i mysql

  4. Mysql underforespørgsel resulterer i where klausul