Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a bytea column to OID while retaining values

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?

like image 769
Petter Avatar asked Apr 13 '12 10:04

Petter


2 Answers

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.

like image 90
Daniel Vérité Avatar answered Sep 30 '22 11:09

Daniel Vérité


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
like image 30
Erwin Brandstetter Avatar answered Sep 30 '22 10:09

Erwin Brandstetter