Convert a bytea column to OID while retaining values

送分小仙女□ 提交于 2019-12-04 04:44:21

问题


I'm trying to alter a bytea column to have type oid and still retain the values.

I have tried using queries like:

ALTER TABLE mytable ADD COLUMN mycol_tmp oid;
UPDATE mytable SET mycol_tmp = CAST(mycol as oid);
ALTER TABLE mytable DROP COLUMN mycol;
ALTER TABLE mytable RENAME mycol_tmp TO mycol;

But that just gives me the error:

ERROR: cannot cast type bytea to oid

Is there any way to achieve what I want?


回答1:


A column of type Oid is just a reference to the binary contents which are actually stored in the system's pg_largeobject table. In terms of storage, an Oid a 4 byte integer. On the other hand, a column of type bytea is the actual contents.

To transfer a bytea into a large object, a new large object should be created with the file-like API of large objects: lo_create() to get a new OID, then lo_open() in write mode, then writes with lo_write() or lowrite(), and then lo_close().

This can't reasonably be done with just a cast.

Basically, you would need to write a ~10 lines piece of code in the language of your choice (at least one that supports the large object API, including plpgsql) to do this conversion.




回答2:


I think the best answer can be found at Grace Batumbya's Blog, in verbis:

The algorithm is pretty simple, get the binary data, if it is null, return null. Else create a large object and in the lowrite function, pass it the binary value, instead of a path to a file.

The code for the procedure is below. Note that the lo_manage package should be installed for this to work.

create or replace function blob_write(lbytea bytea)
   returns oid
   volatile
   language plpgsql as
$f$
   declare
      loid oid;
      lfd integer;
      lsize integer;
begin
   if(lbytea is null) then
      return null;
   end if;

   loid := lo_create(0);
   lfd := lo_open(loid,131072);
   lsize := lowrite(lfd,lbytea);
   perform lo_close(lfd);
   return loid;
end;
$f$;
CREATE CAST (bytea AS oid) WITH FUNCTION blob_write(bytea) AS ASSIGNMENT;

So now the following code works: CREATE TABLE bytea_to_lo ( lo largeObj );

INSERT INTO bytea_to_lo VALUES ( DECODE('00AB','hex'));

I've tried it and works like a charm.




回答3:


Postgres 9.4 adds a built-in function for this:

lo_from_bytea(loid oid, string bytea)

From the release notes:

  • Add SQL functions to allow [large object reads/writes][12] at arbitrary offsets (Pavel Stehule)

For older versions, this is more efficient than what has been posted before:

CREATE OR REPLACE FUNCTION blob_write(bytea)
  RETURNS oid AS
$func$
DECLARE
   loid oid := lo_create(0);
   lfd   int := lo_open(loid, 131072);  -- = 2^17 = x2000
   -- symbolic constant defined in the header file libpq/libpq-fs.h
   -- #define   INV_WRITE   0x00020000
BEGIN
   PERFORM lowrite(lfd, $1);
   PERFORM lo_close(lfd);
   RETURN loid;
END
$func$  LANGUAGE plpgsql VOLATILE STRICT;

The STRICT modifier is smarter than handling NULL manually.

SQL Fiddle.

More in this related answer:

  • Understanding cast from bytea to oid



回答4:


I am sure its late, but for anybody having the same problem in future.

I also faced a similar issue where I had old data in the columns of text directly in the columns not as OIDs. And when I was trying to use that data with upgraded application I too was getting

I used the knowledge of this thread to solve this issue. I strongly feel that whoever stumbles upon this question would surely like to have a look at this here




回答5:


To solve the problem, I successfully used blob_write procedure from Grace Batumbya's Blog: http://gbatumbya.wordpress.com/2011/06/.



来源:https://stackoverflow.com/questions/10139077/convert-a-bytea-column-to-oid-while-retaining-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!