Oracle
 sql >> база данни >  >> RDS >> Oracle

Какъв е алгоритъмът, използван от функцията 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 и изглежда, че 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 от него. Може би ще отделя известно време на това следващата година.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Когато се опитвате да заредите clob в таблица на Oracle, зареждате твърде много записи

  2. Задействайте избиране на дъщерни записи, умножаване на техните стойности и актуализиране на родителски запис

  3. конвертирайте unix_timestamp в timestamp в oracle

  4. Oracle - присъединяване към актуализиране - таблица без ключ

  5. Python cx_Oracle SQL с променлива низ за свързване