Е, ако „изглежда, че се използва“, тогава има смисъл да направите малко обратно инженерство и да проверите какво точно се извиква и да разглобите кода на функцията.
Ако обаче искате да се потопите във вътрешността на Oracle, следното може да ви помогне.
Първо, трябва да разберете как се нарича вътрешна C функция. За да направите това, можете да изпълните дълго работещ код в една сесия. Изпълних това
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);
Това може да бъде и PL/SQL код, просто трябва да сте сигурни, че постоянно извиквате ora_hash.
Докато работи
-
Ако използвате Windows, тогава можете да използвате ostackprof от TANEL PODER(https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack -профилиране-от-sqlplus-използване-ostackprof/ )
-
Ако сте на *nix, можете да използвате dtrace(http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), Flame Graph (сценарий на използване https://blog.dbi -services.com/oracle-database-multilingual-engine-mle/ )
Тествах на Windows и изглежда, че ora_hash е ...->evaopn2()->evahash() ->...
Сега нека потърсим в Google evahash. Извадихме голям късмет, защото има заглавен файл на официалния сайт https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h с връзка към evahash.
И накрая има страница с действителен C код http://burtleburtle.net/bob/hash/ evahash.html
Дотук добре, помним, че можем да използваме външна C функция в Oracle, ако я вградим в библиотека (DLL в Windows).
Например на моя Win x64, ако променя сигнатурата на функцията на
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)
може да се изпълни успешно от Oracle. Но, както виждате, подписът малко се различава от ora_hash в Oracle. Тази функция приема стойност, нейната дължина и initval (може да е начална стойност), докато подписът в Oracle е ora_hash(expr, max_bucket, seed_value).
Нека се опитаме да тестваме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
Нито едно от числата не съвпада. И така, какъв е проблемът? ora_hash приема параметри от почти всякакъв тип (например select ora_hash(sys.odcinumberlist(1,2,3)) from dual
), докато функцията C приема стойност като масив от байтове. Това означава, че известно преобразуване се случва преди извикване на функция. Следователно, преди да използвате споменатата C хеш функция, трябва да разберете как действителната стойност се трансформира, преди да преминете към нея.
Можете да продължите с обратно инженерство на двоични файлове на Oracle, като използвате IDA PRO + шестнадесетични лъчи, но това може да отнеме дни. Да не говорим за конкретни подробности за платформата.
Така че, ако искате да имитирате ora_hash, най-лесният вариант би бил да инсталирате Oracle express edition и да го използвате за извикване на ora_hash.
Надявам се, че беше интересно. Успех.
Актуализация
ora_hash и dbms_utility.get_hash_value могат да бъдат съпоставени един с друг (вижте 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
Ако разопаковаме тялото на пакета на dbms_utility, ще видим следната декларация
function get_hash_value(name varchar2, base number, hash_size number)
return number is
begin
return(icd_hash(name, base, hash_size));
end;
и
function icd_hash(name varchar2,
base binary_integer,
hash_size binary_integer) return binary_integer;
pragma interface(c, icd_hash);
Нека потърсим в Google icd_hash
и можем да открием, че е картографиран към _psdhsh
(https://yurichev.com/blog/50/
). Сега е време да разглобите oracle.exe и да извлечете кода за _psdhsh
от него. Може би ще отделя известно време на това следващата година.