Ответ 1
другая система, которая, как представляется, использует ORA_HASH
Ну, если он "кажется, используется", тогда имеет смысл сделать немного обратной инженерии и проверить, что именно вызывается и дизассемблировать код функции.
Если вы, однако, хотите погрузиться в внутренности 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-profiling-from-sqlplus-using-ostackprof/)
-
Если вы на * nix, то вы можете использовать dtrace (http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html), Пламенный график (сценарий использования 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
С
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
из него. Возможно, я проведу некоторое время в этом следующем году.