un autre système qui semble utiliser ORA_HASH
Eh bien, si elle « semble utiliser » alors il est logique de faire un peu d'ingénierie inverse et vérifier ce qu'on appelle exactement et démonter code du fonction.
Toutefois, si vous souhaitez vous familiariser avec les composants internes d'Oracle, il peut être utile de suivre ce qui suit. Tout d'abord, vous devez déterminer quelle fonction C interne est appelée. Pour ce faire, vous pouvez exécuter du code long en une seule session. J'ai couru cette
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 être un code PL/SQL ainsi, il vous suffit de vous assurer que vous appelez constamment ora_hash.
Alors qu'il est en cours d'exécution
J'ai testé sur Windows et ressemble à ça ora_hash est ...-> evaopn2() ->evahash() -> ...
Maintenant, nous allons google pour evahash. Nous avons eu beaucoup de chance car il y a 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 un lien vers evahash.
Et enfin il y a la page avec le code réel C http://burtleburtle.net/bob/hash/evahash.html
Jusqu'à présent, si bien, nous nous souvenons que nous pouvons utiliser la fonction C externe dans Oracle si nous construisons dans la bibliothèque (DLL sous Windows).
Par exemple sur mon Win x64 si je change la signature de fonction
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 seed) alors 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 numéros matchs. Alors, quel est le problème? ora_hash accepte les paramètres de presque n'importe quel type (par exemple select ora_hash(sys.odcinumberlist(1,2,3)) from dual
) alors que la fonction C accepte la valeur en tant que tableau d'octets. Cela signifie qu'une certaine conversion se produit avant l'appel de fonction. Ainsi, avant d'utiliser la fonction de hachage C mentionnée, vous devez déterminer comment la valeur réelle est transformée avant de passer à elle.
Vous pouvez procéder à la rétro-ingénierie des binaires Oracle à l'aide des rayons hexadécimaux IDA PRO +, mais cela peut prendre plusieurs jours. Sans oublier les 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.
Mise à jour
ora_hash et dbms_utility.get_hash_value peuvent être mis en correspondance les uns aux autres (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 UnWrap corps de paquet de DBMS_UTILITY, nous verrons 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);
Nous allons google pour icd_hash
et nous pouvons trouver qu'il est mappé à _psdhsh
(https://yurichev.com/blog/50/). Maintenant, il est temps de désassembler oracle.exe et d'extraire le code pour _psdhsh
. Je vais peut-être passer du temps sur l'année prochaine.
Si vous souhaitez ré-implémenter un appel pour une application qui n'a pas accès à une base de données réelle, pourquoi avez-vous besoin de ré-implémenter 'ORA_HASH'? Quelle est la magie à ce sujet? Écrivez votre propre fonction de hachage simple sans référence à 'ORA_HASH'. – mathguy
Les mots clés ici sont "faire un appel de service à un autre système." Si j'utilise un algorithme différent, j'obtiendrai une valeur de hachage différente et l'appel ne fonctionnera pas. –
Oh ... je vois; le "autre système" qui "semble utiliser' ORA_HASH' "n'est pas sous votre contrôle. Mon point était, utilisez la même fonction que vous créez dans les deux; mais si vous ne contrôlez qu'un côté, je vois pourquoi vous en avez besoin. – mathguy