PLSQL. Bitwise operations

В plsql отсутствует нативная поддержка побитовых операций, кроме одной - bitand. При необходимости данную возможность можно реализовать самостоятельно. Ниже приведен пример реализации побитового OR и побитового XOR:

-- bit or
function bitor(x number, y number) return number
is
begin
  return (x + y) - bitand(x, y);
end;

-- bit xor
function bitxor(x number, y number) return number
is
begin
  return (x + y) - bitand(x, y) * 2;
end;


Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:

declare
  -- convert binary to decimal
  function bin2dec(binval in varchar2) return number
  is
    l_digits number;
    l_curr_digit char(1);
    l_curr_digit_dec number;
    l_result number := 0;
  begin
    l_digits := length(binval);
   
    for i in 1..l_digits loop
       l_curr_digit := substr(binval, i, 1);
       l_curr_digit_dec := to_number(l_curr_digit);
       l_result := (l_result * 2) + l_curr_digit_dec;
    end loop;
   
    return l_result;
  end;
  
  -- convert decimal to binary
  function dec2bin(p_num number) return varchar2
  is
    binval varchar2(64);
    l_num number := p_num;
  begin
    while (l_num > 0) loop
       binval := mod(l_num, 2) || binval;
       l_num := trunc(l_num / 2);
    end loop;   
    return binval;
  end;
 
  -- bitwise >> for binary
  function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
  is
    l_length number;
    l_shift number;
  begin
    l_length := length(p_bin);
    l_shift := nvl(p_shift, 1);
     
    if (l_length <= 0) then
      return null;
    end if;
     
    if (l_shift > l_length) then
      l_shift := l_length;
    end if;

    return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
  end;

  -- bitwise >> for decimal
  function shift_right(p_num in number, p_shift in number default null) return number
  is
  begin
      if (trunc(p_num) <> p_num or p_num < 0) then
        raise program_error;
      end if;
     
    return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
  end;
 

begin
  dbms_output.put_line(bin2dec('1000')); -- 8
  dbms_output.put_line(shift_right(8, 1)); -- 4
  dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;


Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:

declare
  -- errors bit
  ERROR_FIRST constant integer := 1;      -- 0001
  ERROR_SECOND constant integer := 2; -- 0010
  ERROR_THIRD constant integer := 4;     -- 0100
  ERROR_FOURTH constant integer := 8; -- 1000
 
  -- for capturing errors
  l_errors number := 0;

  -- bit or
  function bitor(x number, y number) return number
  is
  begin
    return (x + y) - bitand(x, y);
  end;

  -- bit xor
  function bitxor(x number, y number) return number
  is
  begin
    return (x + y) - bitand(x, y) * 2;
  end;
  
  -- set error bit
  procedure set_error(p_errors in out number, p_error number)
  is
  begin
    p_errors := bitor(p_errors, p_error);
  end;
 
  -- check if given error captured
  function check_error(p_errors in number, p_error number) return boolean
  is
  begin
    return bitand(p_errors, p_error) = p_error;
  end;
 
  -- print all captured errors
  procedure print_errors(p_errors in number)
  is
    l_err varchar2(4000) := 'Catched errors:';
  begin
    if (check_error(p_errors, ERROR_FIRST)) then
      l_err := l_err || ' ERROR_FIRST,';
    end if;
   
    if (check_error(p_errors, ERROR_SECOND)) then
      l_err := l_err || ' ERROR_SECOND,';
    end if;
   
    if (check_error(p_errors, ERROR_THIRD)) then
      l_err := l_err || ' ERROR_THIRD,';
    end if;
   
    if (check_error(p_errors, ERROR_FOURTH)) then
      l_err := l_err || ' ERROR_FOURTH,';
    end if;
 
    dbms_output.put_line(l_err);
  end;
begin
  set_error(l_errors, ERROR_FIRST);
  set_error(l_errors, ERROR_FOURTH);
 
  print_errors(l_errors);
end;