Bem, se "parece usar", faz sentido fazer um pouco de engenharia reversa e verificar o que exatamente é chamado e desmontar o código da função.
Se você, no entanto, quiser mergulhar nos detalhes internos da Oracle, seguir pode ajudar.
Primeiro de tudo, você precisa descobrir qual função C interna é chamada. Para fazer isso, você pode executar algum código de execução longa em uma sessão.
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Também pode ser código PL/SQL, você só precisa ter certeza de chamar constantemente ora_hash.
Enquanto está em execução
-
Se você estiver no Windows, poderá usar o ostackprof do TANEL PODER ( https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profiling-from-sqlplus-using-ostackprof/ )
-
Se você estiver no *nix, poderá usar o dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (cenário de uso https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Eu testei no Windows e parece que ora_hash é ...->evaopn2()->evahash() ->...
Agora vamos google para evahash. Tivemos muita sorte porque há um arquivo de cabeçalho no site oficial https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h com link para evahash.
E finalmente há uma página com o código C real http://burtleburtle.net/bob/hash/ evahash.html
Até aí tudo bem, lembramos que podemos usar a função C externa no Oracle se a construirmos na biblioteca (DLL no Windows).
Por exemplo, no meu Win x64, se eu alterar a assinatura da função para
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
ele pode ser executado com sucesso no Oracle. Mas, como você vê, a assinatura difere um pouco do ora_hash no Oracle. Esta função aceita valor, seu comprimento e initval (pode ser semente) enquanto a assinatura no Oracle é ora_hash(expr, max_bucket, seed_value).
Vamos tentar testar oOracle
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
Nenhum dos números corresponde. Então, qual é o problema?ora_hash aceita parâmetros de quase qualquer tipo (por exemplo,
select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) enquanto a função C aceita valor como array de bytes. Isso significa que alguma conversão acontece antes da chamada da função. Assim, antes de usar a função hash C mencionada, você precisa descobrir como o valor real é transformado antes de passar para ela. Você pode prosseguir com a engenharia reversa de binários Oracle usando IDA PRO + raios hexadecimais, mas isso pode levar dias. Sem mencionar detalhes específicos da plataforma.
Portanto, se você quiser imitar o ora_hash, a opção mais fácil seria instalar o Oracle express edition e usá-lo para chamar ora_hash.
Espero que tenha sido interessante. Boa sorte.
Atualizar
ora_hash e dbms_utility.get_hash_value podem ser mapeados entre si (consulte 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
Se desempacotarmos o corpo do pacote de dbms_utility, veremos a seguinte declaração
função
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
e
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Vamos pesquisar no Google por
icd_hash
e podemos descobrir que está mapeado para _psdhsh
(https://yurichev.com/blog/50/
). Agora é hora de desmontar oracle.exe e extrair o código para _psdhsh
a partir dele. Talvez eu passe algum tempo nisso no próximo ano.