PostgreSQL: от OID к Bytea

Мы решили перейти от OIDs в нашей базе данных PostgreSQL 9.0 и вместо этого использовать столбцы bytea. Я пытаюсь скопировать данные из одного столбца в другой, но не могу найти правильный запрос. Это самое близкое, что я получил:

update user as thistable set pkcs_as_bytea = (select array_agg(mylargeobject.data) from 
  (select * from pg_largeobject where loid = thistable.pkcs12_as_oid order by pageno) as mylargeobject) where thistable.pkcs12 is not null

И это дает мне следующее сообщение об ошибке:

ERROR:  column "pkcs_as_bytea" is of type bytea but expression is of type bytea[]

Какой тогда будет правильный запрос?


person malaverdiere    schedule 18.02.2011    source источник
comment
array_agg() возвращает массив, поэтому сообщение об ошибке имеет смысл. Как вы думаете, почему вам нужно агрегировать байты там?   -  person a_horse_with_no_name    schedule 18.02.2011
comment
Мне нужно объединить большой двоичный объект, который находится в разных строках oid, в один столбец. Есть ли лучший способ сделать это?   -  person malaverdiere    schedule 21.02.2011


Ответы (4)


Другой способ, не требующий пользовательской функции, — использовать комбинацию loread(lo_open(...)), например:

UPDATE user SET pkcs_as_bytea = loread(lo_open(pkcs12_as_oid, 262144), 1000000) WHERE thistable.pkcs12 IS NOT NULL

Есть проблема с этим кодом, функция loread требует в качестве второго параметра максимальное количество байтов для чтения (параметр 1000000, который я использовал выше), поэтому вы должны использовать здесь действительно большое число, если ваши данные большие. В противном случае содержимое будет обрезано после этого количества байтов, и вы не вернете все данные обратно в поле bytea.

Если вы хотите преобразовать OID в текстовое поле, вы также должны использовать функцию преобразования, например:

UPDATE user SET pkcs_as_text = convert_from(loread(lo_open(pkcs12_as_oid, 262144), 1000000), 'UTF8')

(262144 — флаг открытого режима, 40000 в шестнадцатеричном формате, что означает «открыть только для чтения»)

person Sergiu Dumitriu    schedule 28.04.2012
comment
Отличное и хорошо объясненное решение. - person gersonZaragocin; 28.03.2015

Вот хранимая процедура, которая творит чудеса:

CREATE OR REPLACE FUNCTION merge_oid(val oid) 
returns bytea as $$
declare merged bytea;
declare arr bytea;
 BEGIN  
   FOR arr IN SELECT data from pg_largeobject WHERE loid = val ORDER BY pageno LOOP
     IF merged IS NULL THEN
       merged := arr;
     ELSE
       merged := merged || arr;
     END IF;
   END LOOP;
  RETURN merged;

END  
$$ LANGUAGE plpgsql;
person malaverdiere    schedule 21.02.2011

ну, я сделал что-то вроде этого. У меня есть таблица вложений и столбец содержимого с данными в типе oid. Я мигрировал с четырьмя действиями:

ALTER TABLE attachment add column content_bytea bytea
UPDATE attachment SET content_bytea = lo_get(content)
ALTER TABLE attachment drop column content
ALTER TABLE attachment rename column content_bytea to content
person Ilya Khudyakov    schedule 27.02.2019

Вам нужно что-то вроде array_to_string(anyarray, text) для текстовых массивов, но в данном случае array_to_bytea(largeobjectarray) для объединения всех разделов. Вы должны создать эту функцию самостоятельно или обработать ее в логике приложения.

person Frank Heikens    schedule 18.02.2011