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
-
Si usa Windows, puede usar ostackprof de TANEL PODER (https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -perfilado-desde-sqlplus-usando-ostackprof/ )
-
Si usa *nix, puede usar dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (escenario de uso https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
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.