The cast is not a true cast. It's just (ab)using the convenient syntax. A large object (LO) is created in the background which is stored separately and the OID referencing it is returned.
Per documentation:
All large objects are stored in a single system table named
pg_largeobject. Each large object also has an entry in the system
table pg_largeobject_metadata. Large objects can be created, modified,
and deleted using a read/write API that is similar to standard
operations on files.
The returned OID is basically a FK to the PK of the system table pg_largeobject.
CREATE TABLE is completely independent from the function and pseudo-cast.
CREATE TABLE bytea_to_lo (
largeObj lo
);
It's just a typical use case for the assignment cast created above, which becomes apparent from the following line that you forgot to quote:
INSERT INTO bytea_to_lo VALUES (DECODE('00AB','hex'));
What happens here?
The data type lo is a domain over the base type oid, created by the additional module lo (incorrectly referenced as "lo_manage package" in the blog enty of Grace Batumbya). Per documentation:
The module also provides a data type lo, which is really just a domain
of the oid type. This is useful for differentiating database columns
that hold large object references from those that are OIDs of other things.
The function decode() returns bytea. The INSERT statement assigns the bytea value to the column largeObj, which triggers an assignment cast to its type lo, and that's where the above cast comes in.
Warning / Corrective / Update
The blog entry is sloppy and outdated by now.
Does not bother to mention that (per documentation):
To be able to create a cast, you must own the source or the target
data type and have USAGE privilege on the other type.
Effectively, you must be superuser.
Typo in CREATE TABLE: column name and type reversed.
The function definition is verbose and inefficient. This would be better (for Postgres 9.3 or older):
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;
SQL Fiddle.
There is a built-in function for this in Postgres 9.4. Use that instead:
lo_from_bytea(loid oid, string bytea)
From the release notes:
For CREATE CAST (per documentation):
The first argument type must be identical to or binary-coercible from the cast's source type.
I suggest an overloaded variant with only a bytea parameter:
CREATE OR REPLACE FUNCTION lo_from_bytea(bytea)
RETURNS oid LANGUAGE sql AS
'SELECT lo_from_bytea(0, $1)';
CREATE CAST (bytea AS oid) WITH FUNCTION lo_from_bytea(bytea) AS ASSIGNMENT;
Since the pseudo-cast has quite a big side effect, I am not convinced to make that an ASSIGNMENT cast. I'd probably start with explicit-only: