7

bigintより多くのデータを保持するために列をbyteaバイトに変更したいPostgreSQLテーブルがあります。私は次のシーケンスを使用して考えています:

  1. alter table mytable add new_column
  2. update mytable set new_column = int8send(old_column)
  3. alter table drop old_column
  4. alter table rename new_column to old_column

上記のシーケンスは機能しますが、唯一の問題は、のバイトシーケンスをbyteaにすることです。たとえば、の値がである場合、上記のシーケンスはを生成しますが、私はそれをにしたいと思います 。結果は、発信元からのビッグエンディアンの順序を使用しているようです。old_column0x1234567890abcdef\0224Vx\220\253\315\357\357\315\253\220xV4\022byteabigint

プログラムを書かずにそれを行う簡単な方法はありますか?swap64()PostgreSQLである種の関数を探していましたが、見つかりませんでした。

4

4 に答える 4

3

16進表現で正規表現抽出を使用すると、plpgsqlコードなしでバイトスワップすることができます。これは、bigint定数を交換する例SET standard_conforming_strings to ONです(PG 9.1のデフォルト)

select regexp_replace( lpad(to_hex(x'123456789abcd'::bigint),16,'0'),
 '(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)',
 '\8\7\6\5\4\3\2\1');

を返しますcdab896745230100。次にdecode(value, 'hex')、それをビテアに変換するために適用します。

型変換全体は、実際には単一のSQLステートメントで実行できます。

ALTER TABLE mytable ALTER COLUMN old_column TYPE bytea
  USING decode(
    regexp_replace( lpad(to_hex(old_column), 16,'0'),
 '(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)',
 '\8\7\6\5\4\3\2\1')
  , 'hex');
于 2012-06-22T00:24:31.923 に答える
3

byteaこれは、型の値のバイト順を逆にするために私が書いた純粋な SQL 関数です。

CREATE OR REPLACE FUNCTION reverse_bytes_iter(bytes bytea, length int, midpoint int, index int)
RETURNS bytea AS
$$
  SELECT CASE WHEN index >= midpoint THEN bytes ELSE
    reverse_bytes_iter(
      set_byte(
        set_byte(bytes, index, get_byte(bytes, length-index)),
        length-index, get_byte(bytes, index)
      ),
      length, midpoint, index + 1
    )
  END;
$$ LANGUAGE SQL IMMUTABLE;

CREATE OR REPLACE FUNCTION reverse_bytes(bytes bytea) RETURNS bytea AS
'SELECT reverse_bytes_iter(bytes, octet_length(bytes)-1, octet_length(bytes)/2, 0)'
LANGUAGE SQL IMMUTABLE;

昨日書いたばかりなので、特に十分にテストも最適化もされていませんが、少なくとも長さが1kまでのバイト文字列では機能するようです。

于 2014-08-05T11:08:57.447 に答える
1

私は現在pageinspectモジュールで遊んでいます。また、既存の bytea 値のバイト順を変更する方法も気になりました。これは、あなたのケースとほぼ一致します。

私は次の機能を思いついた:

CREATE OR REPLACE FUNCTION reverse(bytea) RETURNS bytea AS $reverse$
    SELECT string_agg(byte,''::bytea)
      FROM (
        SELECT substr($1,i,1) byte
          FROM generate_series(length($1),1,-1) i) s
$reverse$ LANGUAGE sql;

これは非常に簡単で、テキストreverse()関数と同様に機能します。

WITH v(val) AS (
    VALUES ('\xaabbccdd'::bytea),('\x0123456789abcd'::bytea)
)
SELECT val, reverse(val)
  FROM v;
于 2014-10-21T19:24:24.630 に答える
0

この関数は、まさに探しているものではありませんが、道を進むのに役立つはずです。

その関数のソース コードを以下にそのまま再現します。

CREATE OR REPLACE FUNCTION utils.int_littleendian(v_number integer) 
  RETURNS bytea AS 
$BODY$ 
DECLARE 
        v_textresult bytea; 
        v_temp int; 
        v_int int; 
        v_i int = 0; 
BEGIN 
        v_int = v_number; 
        v_textresult = '1234'; 
        WHILE(v_i < 4) LOOP 
                raise notice 'loop %',v_int; 
                v_temp := v_int%256; 
                v_int := v_int - v_temp; 
                v_int := v_int / 256; 
                SELECT set_byte(v_textresult,v_i,v_temp) INTO v_textresult; 
                v_i := v_i + 1; 
        END LOOP; 
        return v_textresult; 
END; 

$BODY$ 
  LANGUAGE 'plpgsql' VOLATILE 
  COST 100; 
于 2012-06-21T18:32:51.523 に答える