2012-04-13 60 views
2

我试图将bytea列更改为oid并仍保留值。将bytea列转换为OID,同时保留值

我一直在使用类似的查询尝试:

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; 

但只是给我的错误:

ERROR: cannot cast type bytea to oid 

有没有什么方法可以达到我想要什么?

+0

相关:http://stackoverflow.com/questions/29433041/understanding-cast-from-bytea-to-oid – 2015-04-03 17:07:30

回答

4

Oid类型的列只是对二进制内容的引用,它实际上存储在系统的pg_largeobject表中。在存储方面,Oid是一个4字节的整数。另一方面,类型bytea 的列是的实际内容。

要将bytea传输到大对象中,应该使用类似文件的大对象API创建新的大对象:lo_create()以获取新的OID,然后在写模式下使用lo_open(),然后使用lo_write()或lowrite(),然后是lo_close()。

这只能通过演员阵容才能合理完成。

基本上,您需要用您选择的语言(至少一个支持大对象API,包括plpgsql)编写一行~10行的代码来执行此转换。

+0

谢谢你你的答案!我意识到一个OID与bytea非常不同,但我认为有一些查询可以用来将bytea的内容放入oid引用。用另一种语言来做这件事不会是个大问题。再次感谢! – Petter 2012-04-13 12:39:43

+0

我错在缺少将数据写入大对象的服务器端写入函数,因此我已经编辑了相应的答案。事实证明,它被称为lowrite(不是lo_write),它在文档中没有提及,但它肯定可以用于复制步骤。 – 2012-04-17 09:15:18

0

为了解决这个问题,我成功地使用了Grace Batumbya的博客中的blob_write过程:http://gbatumbya.wordpress.com/2011/06/

+2

请详细说明至少引用最相关的位。链接腐烂发生。 – 2012-08-28 09:03:28

4

我认为最好的答案可以在Grace Batumbya's Blog发现,在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')); 

我已经尝试过了,就像一个魅力。

2

的Postgres 9.4增加了对这个built-in function

lo_from_bytea(loid oid, string bytea) 

release notes

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

对于旧版本,这比什么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; 

STRICT修饰符比手动处理NULL更聪明。

SQL Fiddle.

内其他相关答案:

0

我相信它的晚,但对任何人有在未来同样的问题。

我也遇到了类似的问题,我在列中直接在列中的旧数据而不是OID。当我试图使用升级的应用程序的数据时,我也得到了

我用这个线程的知识来解决这个问题。我强烈地感到,谁在这个问题上发生了什么,肯定会喜欢看这个here

相关问题