了解从 bytea 到 oid 的转换

Understanding cast from bytea to oid

我正在使用 PostgreSQL 9.2
This blog entry by Grace Batumbya 提供从 byteaoid 的转换。

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;

CREATE TABLE bytea_to_lo (
   largeObj lo 
);

我不明白为什么要创建bytea_to_lo table? PostgreSQL 将如何使用它?

该演员不是真正的演员。它只是(ab)使用方便的语法。后台创建一个large object (LO)单独存储,返回引用它的OID

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.

返回的OID基本上是FK对系统PK的FKtablepg_largeobject.

CREATE TABLE完全独立于函数和伪投。

CREATE TABLE bytea_to_lo (
   largeObj lo 
);

这只是上面创建的赋值转换的典型用例,从您忘记引用的以下行中可以看出这一点:

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

这里发生了什么?

数据类型 lo 是基本类型 oid 的域,由附加模块 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.

函数decode()returnsbyteaINSERT 语句将 bytea 值分配给列 largeObj,这会触发对其类型 lo 的赋值转换,这就是上述转换的用武之地。

警告/更正/更新

博客条目草率且过时。

  • 懒得提那个(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.

    实际上,您必须是超级用户。

  • CREATE TABLE 中的拼写错误:列名和类型颠倒了。

  • 函数定义冗长且效率低下。这会更好(对于 Postgres 9.3 或更早版本):

    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, );
       PERFORM lo_close(lfd);
       RETURN loid;
    END
    $func$  LANGUAGE plpgsql VOLATILE STRICT;
    

    SQL Fiddle.

在 Postgres 9.4 中有一个 built-in function。改用它:

lo_from_bytea(loid oid, string bytea)

来自release notes:

对于CREATE CAST (per documentation):

The first argument type must be identical to or binary-coercible from the cast's source type.

我建议使用只有一个 bytea 参数的重载变体:

CREATE OR REPLACE FUNCTION lo_from_bytea(bytea)
   RETURNS oid LANGUAGE sql AS
'SELECT lo_from_bytea(0, )';

CREATE CAST (bytea AS oid) WITH FUNCTION lo_from_bytea(bytea) AS ASSIGNMENT;

由于伪演员有相当大的副作用,我不相信将其设为 ASSIGNMENT 演员。我可能会从仅显式开始:

  • Generate series of dates - using date type as input