Преобразовать байту в двоичную строку - PullRequest
1 голос
/ 06 мая 2019

Мне нужно декодировать строку base64 и взять кусок двоичного кода.

Есть ли в Postgres функция SQL для простого преобразования bytea в двоичное строковое представление?
(Например, "00010001010101010" .)

Ответы [ 2 ]

1 голос
/ 06 мая 2019

Если ваша установка Postgres работает с bytea_output с настройкой по умолчанию hex, существует очень простой взлом:

SELECT right((bytea '\xDEADBEEF')::text, -1)::varbit

Результат:

'11011110101011011011111011101111'

right(text, -1) - это самый дешевый способ удалить начальную обратную косую черту из текстового представления.

varbit (или его официальное имя в стандартном SQL: bit varying) для битовых строк произвольной длины.Приведите результат к text или varchar, если хотите.

Связано с объяснением:

1 голос
/ 06 мая 2019

демо: дб <> скрипка

Вы можете поместить следующий код в функцию:

WITH byte AS (   -- 1
    SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
    string_agg(      -- 5
        get_byte(value, gs)::bit(8)::text -- 4
        , ''
    )
FROM 
    byte,
    generate_series(        -- 3
        0, 
        length(value) - 1   -- 2
    ) gs

Я продемонстрировал разработку запроса в скрипке.

  1. Предложение WITH инкапсулирует значение bytea для двойного использования в следующем коде
  2. length() вычисляет двоичную длину значения bytea
  3. generate_series() создает список от 0 до length - 1 (0 - 3 в моем примере)
  4. get_byte() принимает значение bytea во второй раз и выдает байт в позиции gs (предыдущие вычисленные значения 0-3). Это дает integer представление байта. После этого приведение к типу bit(8) преобразует результат этой функции в ее двоичное представление (1 байт = 8 бит)
  5. string_agg() наконец-то объединяет все двоичные строки в одну. (принимает его text представления вместо bit типа, без разделителей)

Функция может выглядеть так:

CREATE OR REPLACE FUNCTION to_bit(value bytea) RETURNS SETOF text AS 
$$
BEGIN
    RETURN QUERY 
        SELECT
            string_agg(get_byte(value, gs)::bit(8)::text, '')
        FROM 
            generate_series(0, length(value) - 1) gs;
END;
$$ LANGUAGE plpgsql;

После этого вы можете назвать это:

SELECT to_bit(E'\\xDEADBEEF'::bytea)

Вы можете попробовать это, используя get_bit() вместо get_byte(). Это обезопасит вас от применения ::bit(8), но, конечно, вам нужно умножить длину на коэффициент 8.

Полученная битовая строка имеет другой битовый порядок, но, возможно, она лучше подходит для вашего варианта использования:

WITH byte AS (
    SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
    string_agg(get_bit(value, gs)::text, '')
FROM 
    byte,
    generate_series(0, length(value) * 8 - 1) gs

демо: дб <> скрипка

...