如何将数字转换为字节,类似于 postgres 中的 java

how to convert numeric to byte as similer to java in postgres

我正在尝试在 Postgres 中复制一些 java 代码。

我需要执行的操作是将Java BigInteger转换为byte array

Java代码:

public class Main {
    public static void main(String[] args) {
         BigInteger n = new BigInteger("1677259342285725925376");
         System.out.println(Arrays.toString(n.toByteArray()));
    }

}

输出: [90, -20, -90, 53, 78, -38, 2, -128, 0]

Postgres 代码:

select  numeric_send(1677259342285725925376);

输出: "[=18=]0[=18=]6[=18=]0[=18=]5[=18=]0[=18=]0[=18=]0[=18=]0[=18=]006-$~3)2 5[=18=]0"

使用 numeric_send 将数字转换为 bytea http://www.leadum.com/downloads/dbscribe/samples/postgresql/web_modern/function/main/643567399.html

为了检查 Java 控制台中的输出,我在下面写了匿名块

do 
$$
declare
bytes bytea;
begin
bytes := numeric_send(1677259342285725925376);
for i in 0..length(bytes)-1 loop
 raise notice '%', get_byte(bytes,i);
end loop;
end; $$

现在输出打印为:

NOTICE:  0
NOTICE:  6
NOTICE:  0
NOTICE:  5
NOTICE:  0
NOTICE:  0
NOTICE:  0
NOTICE:  0
NOTICE:  0
NOTICE:  16
NOTICE:  30
NOTICE:  45
NOTICE:  36
NOTICE:  126
NOTICE:  11
NOTICE:  41
NOTICE:  10
NOTICE:  32
NOTICE:  21
NOTICE:  0

根据我的说法,输出应该与我在两者中转换为字节数组的输出相同。请帮助我如何实现相同的目标。

谢谢

PostgreSQL 的 numeric 和 Java 的 java.math.BigInteger 有不同的二进制表示。

numeric 是一个二进制编码的十进制,你也有 varlena header。

尽可能避免使用数据类型的内部二进制表示——这可能取决于机器架构的字节顺序等因素。

我执行了以下步骤将数值转换为字节数组。

-- Convert numeric to bit
CREATE OR REPLACE FUNCTION numeric_to_bit(NUMERIC)
  RETURNS BIT VARYING AS $$
DECLARE
  num ALIAS FOR ;
  -- 1 + largest positive BIGINT --
  max_bigint NUMERIC := '9223372036854775808' :: NUMERIC(19, 0);
  result BIT VARYING;
BEGIN
  WITH
      chunks (exponent, chunk) AS (
        SELECT
          exponent,
          floor((num / (max_bigint ^ exponent) :: NUMERIC(300, 20)) % max_bigint) :: BIGINT
        FROM generate_series(0, 5) exponent
    )
  SELECT bit_or(chunk :: BIT(300) :: BIT VARYING << (63 * (exponent))) :: BIT VARYING
  FROM chunks INTO result;
  RETURN result;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- conversion for bit(8) to integer with sign
CREATE OR REPLACE FUNCTION bit_to_integer(b BIT(8))
  RETURNS INTEGER  AS $$
DECLARE
  result int;
BEGIN
  result := b::integer;
  result := case when result > 127 then result-256 else result end;
  RETURN result;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- removce padding from bit varying
CREATE OR REPLACE FUNCTION ltrim_bitvar(bv BIT VARYING)
  RETURNS text  AS $$
DECLARE
  result text;
  fill int;
BEGIN
  result := ltrim(bv::text,'0');
  fill := 8-length(result)%8;
  result := lpad(result,length(result)+fill,'0') ;
  return result;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

--converting bit var text to byte array
CREATE OR REPLACE FUNCTION btext_to_bytea(b text)
  RETURNS bytea AS
$BODY$
DECLARE
  bytes bytea;
  temp integer;
  b_len integer;
BEGIN
  b_len := length(b)/8;
  bytes = lpad('',b_len,'0')::bytea;
  for i in 1..b_len loop
   temp = substring(b,(i*8)-8 + 1,8)::bit(8)::integer;
   --raise notice '%', temp;
   bytes := set_byte(bytes, i-1, temp);
  end loop;
  return bytes;

END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE;

-- converting numeric to bytea
CREATE OR REPLACE FUNCTION num_to_bytea(n numeric)
  RETURNS bytea AS
$BODY$

BEGIN
 return btext_to_bytea(ltrim_bitvar(numeric_to_bit(n)));
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE;

创建以上必备功能。

do 
$$
declare
bytes bytea;
begin
bytes := num_to_bytea(1677259342285725925376::numeric);
for i in 0..length(bytes)-1 loop
 raise notice '%',  case when get_byte(bytes,i) > 127 then get_byte(bytes,i)-256 else get_byte(bytes,i) end ;
end loop;
end; $$

输出:

NOTICE:  90
NOTICE:  -20
NOTICE:  -90
NOTICE:  53
NOTICE:  78
NOTICE:  -38
NOTICE:  2
NOTICE:  -128
NOTICE:  0