sql >> Base de Datos >  >> RDS >> Oracle

¿Cuál es el algoritmo utilizado por la función ORA_HASH?

Bueno, si "parece usarse", entonces tiene sentido hacer un poco de ingeniería inversa y verificar cómo se llama exactamente y desensamblar el código de la función.

Sin embargo, si desea sumergirse en los aspectos internos de Oracle, lo siguiente puede ser de ayuda.

En primer lugar, debe averiguar cómo se llama la función C interna. Para hacerlo, puede ejecutar un código de ejecución prolongada en una sesión. Ejecuté esto

select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);

También puede ser código PL/SQL, solo debe asegurarse de llamar constantemente a ora_hash.

Mientras se está ejecutando

Probé en Windows y parece que ora_hash es ...->evaopn2()->evahash() ->...

Ahora busquemos evahash en Google. Tuvimos mucha suerte porque hay un archivo de encabezado en el sitio oficial https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h con enlace a evahash.

Y finalmente hay una página con código C real http://burtleburtle.net/bob/hash/ evahash.html

Hasta aquí todo bien, recordamos que podemos usar la función C externa en Oracle si la integramos en la biblioteca (DLL en Windows).

Por ejemplo, en mi Win x64 si cambio la firma de la función a

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

se puede ejecutar con éxito desde Oracle. Pero, como puede ver, la firma difiere un poco de ora_hash en Oracle. Esta función acepta valor, su longitud y valor inicial (puede ser inicial) mientras que la firma en Oracle es ora_hash (expr, max_bucket, seed_value).

Intentemos probar Oracle

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

Ninguno de los números coincide. Entonces, ¿cuál es el problema? ora_hash acepta parámetros de casi cualquier tipo (por ejemplo, select ora_hash(sys.odcinumberlist(1,2,3)) from dual ) mientras que la función C acepta el valor como matriz de bytes. Esto significa que alguna conversión ocurre antes de la llamada a la función. Por lo tanto, antes de usar la función hash C mencionada, debe averiguar cómo se transforma el valor real antes de pasarlo.

Puede continuar con la ingeniería inversa de los binarios de Oracle utilizando IDA PRO + rayos hexadecimales, pero eso puede llevar días. Sin mencionar los detalles específicos de la plataforma.

Entonces, si desea imitar ora_hash, la opción más fácil sería instalar la edición Oracle Express y usarla para llamar a ora_hash.

Espero que haya sido interesante. Buena suerte.

Actualizar

ora_hash y dbms_utility.get_hash_value se pueden asignar entre sí (ver 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

Si desenvolvemos el cuerpo del paquete de dbms_utility, veremos la siguiente declaración

  function get_hash_value(name varchar2, base number, hash_size number)
    return number is
  begin
    return(icd_hash(name, base, hash_size));
  end;

y

  function icd_hash(name      varchar2,
                    base      binary_integer,
                    hash_size binary_integer) return binary_integer;
  pragma interface(c, icd_hash);

Busquemos en Google icd_hash y podemos encontrar que está asignado a _psdhsh (https://yurichev.com/blog/50/ ). Ahora es el momento de desensamblar oracle.exe y extraer el código para _psdhsh de eso. Tal vez dedique algo de tiempo a esto el próximo año.