Eh bien, s'il "semble utiliser", il est logique de faire un peu de rétro-ingénierie et de vérifier exactement ce qu'on appelle et de désassembler le code de la fonction.
Toutefois, si vous souhaitez vous plonger dans les composants internes d'Oracle, ce qui suit peut vous aider.
Tout d'abord, vous devez comprendre comment s'appelle la fonction C interne. Pour ce faire, vous pouvez exécuter du code long en une seule session. J'ai exécuté ceci
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Il peut également s'agir de code PL/SQL, il vous suffit de vous assurer que vous appelez constamment ora_hash.
Pendant qu'il tourne
-
Si vous utilisez Windows, vous pouvez utiliser ostackprof de TANEL PODER (https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -profilage-de-sqlplus-using-ostackprof/ )
-
Si vous êtes sur * nix, vous pouvez utiliser dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (scénario d'utilisation https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
J'ai testé sur Windows et on dirait que ora_hash est ...->evaopn2()->evahash() ->...
Maintenant, cherchons evahash sur Google. Nous avons eu beaucoup de chance car il existe un fichier d'en-tête sur le site officiel https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h avec lien vers evahash.
Et enfin il y a une page avec le code C réel http://burtleburtle.net/bob/hash/ evahash.html
Jusqu'ici tout va bien, nous nous souvenons que nous pouvons utiliser la fonction C externe dans Oracle si nous la créons dans une bibliothèque (DLL sous Windows).
Par exemple sur mon Win x64 si je change la signature de la fonction en
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
il peut être exécuté avec succès à partir d'Oracle.Mais, comme vous le voyez, la signature diffère un peu de ora_hash dans Oracle. Cette fonction accepte la valeur, sa longueur et initval (peut être une graine) tandis que la signature dans Oracle est ora_hash(expr, max_bucket, seed_value).
Essayons de tester 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
Aucun des nombres ne correspond.Alors quel est le problème ?ora_hash accepte des paramètres de presque tous les types (par exemple, select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) tandis que la fonction C accepte la valeur sous forme de tableau d'octets. Cela signifie qu'une certaine conversion se produit avant l'appel de la fonction.Ainsi, avant d'utiliser la fonction de hachage C mentionnée, vous devez comprendre comment la valeur réelle est transformée avant de lui passer.
Vous pouvez procéder à l'ingénierie inverse des binaires Oracle en utilisant les rayons hexadécimaux IDA PRO +, mais cela peut prendre des jours. Sans parler des détails spécifiques à la plate-forme.
Donc, si vous voulez imiter ora_hash, l'option la plus simple serait d'installer Oracle express edition et de l'utiliser pour appeler ora_hash.
J'espère que c'était intéressant. Bonne chance.
Mettre à jour
ora_hash et dbms_utility.get_hash_value peuvent être mappés l'un à l'autre (voir 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 nous déballons le corps du package de dbms_utility, nous verrons la déclaration suivante
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
et
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Cherchons icd_hash
sur Google et nous pouvons trouver qu'il est mappé sur _psdhsh
(https://yurichev.com/blog/50/
). Il est maintenant temps de désassembler oracle.exe et d'extraire le code pour _psdhsh
à partir de cela. Peut-être que j'y consacrerai du temps l'année prochaine.