2012-04-13 62 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

相關問題