sql >> Database >  >> RDS >> Oracle

Wat is het algoritme dat wordt gebruikt door de ORA_HASH-functie?

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

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.



  1. Database-ontwerp om on-the-fly tabellen te maken

  2. Symfony2:Basistabel of weergave niet gevonden:1146

  3. error:subquery mag slechts één kolom retourneren

  4. Python en MySQL:is er een alternatief voor MySQLdb?