【问题标题】:how to convert numeric to byte as similer to java in postgres如何将数字转换为字节,类似于 postgres 中的 java
【发布时间】:2019-08-23 08:11:05
【问题描述】:

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

我需要执行的操作是将JavaBigInteger转换为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);

输出: "\000\006\000\005\000\000\000\000\000\020\036-$~\013)\012 \025\000"

使用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

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

谢谢

【问题讨论】:

  • 为什么在 Postgres 中需要它?您试图解决的根本问题是什么?
  • @a_horse_with_no_name 我们在 postgres 中使用plpythonu 扩展来进行此类操作,因为AWS RDS 不支持plpythonu。所以,我们需要在 postgres 中创建这些函数。

标签: java arrays postgresql bytea


【解决方案1】:

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

numeric 是二进制编码的十进制,您也有 varlena 标头。

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

【讨论】:

    【解决方案2】:

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

    -- Convert numeric to bit
    CREATE OR REPLACE FUNCTION numeric_to_bit(NUMERIC)
      RETURNS BIT VARYING AS $$
    DECLARE
      num ALIAS FOR $1;
      -- 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
    

    【讨论】:

      猜你喜欢
      • 2018-02-14
      • 2019-12-23
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      • 2012-07-18
      • 2018-06-24
      相关资源
      最近更新 更多