*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 3399,3404 **** SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
--- 3399,3462 ----
See also the aggregate function string_agg in
.
+
+
+
+
+ See also a description of other Large Objects Function
+ in .
+
*** a/doc/src/sgml/lobj.sgml
--- b/doc/src/sgml/lobj.sgml
***************
*** 580,585 **** SELECT lo_export(image.raster, '/tmp/motd') FROM image
--- 580,608 ----
these functions as loread> and lowrite>.
+
+ There are other two functions , that doesn't correspond with client api
+ (see in ).
+ make_lo transforms a binary string to lo object, and
+ load_lo transforms a lo object to binary string.
+
+
+
+ Some examples:
+
+ SELECT make_lo(decode('ffffff00','hex'));
+ make_lo
+ ---------
+ 24629
+ (1 row)
+
+ SELECT load_lo(24628);
+ load_lo
+ -----------
+ \xffffff00
+ (1 row)
+
+
*** a/src/backend/libpq/be-fsstubs.c
--- b/src/backend/libpq/be-fsstubs.c
***************
*** 754,756 **** deleteLOfd(int fd)
--- 754,848 ----
{
cookies[fd] = NULL;
}
+
+ /*****************************************************************************
+ * LO simplified SQL API for manipulation with LO
+ *****************************************************************************/
+
+ /*
+ * load LO and return it as bytea
+ */
+ Datum
+ load_lo(PG_FUNCTION_ARGS)
+ {
+ Oid loOid = PG_GETARG_OID(0);
+ LargeObjectDesc *loDesc;
+ int64 len;
+ int total_read;
+ bytea *result = NULL;
+
+ /*
+ * We don't actually need to store into fscxt, but create it anyway to
+ * ensure that AtEOXact_LargeObject knows there is state to clean up
+ */
+ CreateFSContext();
+
+ loDesc = inv_open(loOid, INV_READ, fscxt);
+
+ /* Permission check */
+ if (!lo_compat_privileges &&
+ pg_largeobject_aclcheck_snapshot(loDesc->id,
+ GetUserId(),
+ ACL_SELECT,
+ loDesc->snapshot) != ACLCHECK_OK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for large object %u",
+ loDesc->id)));
+
+ len = inv_seek(loDesc, 0, SEEK_END);
+ inv_seek(loDesc, 0, SEEK_SET);
+
+ result = (bytea *) palloc(VARHDRSZ + len);
+ total_read = inv_read(loDesc, VARDATA(result), len);
+
+ Assert(total_read == len);
+
+ inv_close(loDesc);
+
+ SET_VARSIZE(result, total_read + VARHDRSZ);
+
+ PG_RETURN_BYTEA_P(result);
+ }
+
+ /*
+ * internal - shared code for make_lo and make_lo_with_oid
+ */
+ static Oid
+ make_lo_internal(bytea *str, Oid loOid)
+ {
+ LargeObjectDesc *loDesc;
+
+ CreateFSContext();
+
+ loOid = inv_create(loOid);
+ loDesc = inv_open(loOid, INV_WRITE, fscxt);
+ inv_write(loDesc, VARDATA_ANY(str),
+ VARSIZE_ANY_EXHDR(str));
+ inv_close(loDesc);
+
+ return loOid;
+ }
+
+ /*
+ * Save bytea to LO
+ */
+ Datum
+ make_lo(PG_FUNCTION_ARGS)
+ {
+ bytea *str = PG_GETARG_BYTEA_PP(0);
+
+ PG_RETURN_OID(make_lo_internal(str, InvalidOid));
+ }
+
+ /*
+ * Save bytea to LO with specified loOid
+ */
+ Datum
+ make_lo_with_oid(PG_FUNCTION_ARGS)
+ {
+ bytea *str = PG_GETARG_BYTEA_PP(0);
+ Oid loOid = PG_GETARG_OID(1);
+
+ PG_RETURN_OID(make_lo_internal(str, loOid));
+ }
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 1055,1060 **** DESCR("truncate large object");
--- 1055,1067 ----
DATA(insert OID = 3172 ( lo_truncate64 PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 23 "23 20" _null_ _null_ _null_ _null_ lo_truncate64 _null_ _null_ _null_ ));
DESCR("truncate large object (64 bit)");
+ DATA(insert OID = 3178 ( load_lo PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 17 "26" _null_ _null_ _null_ _null_ load_lo _null_ _null_ _null_ ));
+ DESCR("load large object to bytea");
+ DATA(insert OID = 3179 ( make_lo PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 26 "17" _null_ _null_ _null_ _null_ make_lo _null_ _null_ _null_ ));
+ DESCR("save bytea to large object");
+ DATA(insert OID = 3180 ( make_lo PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 26 "17 26" _null_ _null_ _null_ _null_ make_lo_with_oid _null_ _null_ _null_ ));
+ DESCR("save bytea to large object");
+
DATA(insert OID = 959 ( on_pl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "600 628" _null_ _null_ _null_ _null_ on_pl _null_ _null_ _null_ ));
DATA(insert OID = 960 ( on_sl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "601 628" _null_ _null_ _null_ _null_ on_sl _null_ _null_ _null_ ));
DATA(insert OID = 961 ( close_pl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 600 "600 628" _null_ _null_ _null_ _null_ close_pl _null_ _null_ _null_ ));
*** a/src/include/libpq/be-fsstubs.h
--- b/src/include/libpq/be-fsstubs.h
***************
*** 46,51 **** extern Datum lo_truncate64(PG_FUNCTION_ARGS);
--- 46,58 ----
extern bool lo_compat_privileges;
/*
+ * Simplified LO API
+ */
+ extern Datum load_lo(PG_FUNCTION_ARGS);
+ extern Datum make_lo(PG_FUNCTION_ARGS);
+ extern Datum make_lo_with_oid(PG_FUNCTION_ARGS);
+
+ /*
* These are not fmgr-callable, but are available to C code.
* Probably these should have had the underscore-free names,
* but too late now...
*** a/src/test/regress/input/largeobject.source
--- b/src/test/regress/input/largeobject.source
***************
*** 203,207 **** SELECT pageno, data FROM pg_largeobject WHERE loid = :newloid;
--- 203,219 ----
SELECT lo_unlink(loid) FROM lotest_stash_values;
\lo_unlink :newloid
+ \lo_import 'results/lotest.txt'
+
+ \set newloid_1 :LASTOID
+
+ SELECT make_lo(load_lo(:newloid_1)) AS newloid_2
+ \gset
+
+ SELECT md5(load_lo(:newloid_1)) = md5(load_lo(:newloid_2));
+
+ \lo_unlink :newloid_1
+ \lo_unlink :newloid_2
+
TRUNCATE lotest_stash_values;
DROP ROLE regresslo;
*** a/src/test/regress/output/largeobject.source
--- b/src/test/regress/output/largeobject.source
***************
*** 391,395 **** SELECT lo_unlink(loid) FROM lotest_stash_values;
--- 391,407 ----
(1 row)
\lo_unlink :newloid
+ \lo_import 'results/lotest.txt'
+ \set newloid_1 :LASTOID
+ SELECT make_lo(load_lo(:newloid_1)) AS newloid_2
+ \gset
+ SELECT md5(load_lo(:newloid_1)) = md5(load_lo(:newloid_2));
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ \lo_unlink :newloid_1
+ \lo_unlink :newloid_2
TRUNCATE lotest_stash_values;
DROP ROLE regresslo;
*** a/src/test/regress/output/largeobject_1.source
--- b/src/test/regress/output/largeobject_1.source
***************
*** 391,395 **** SELECT lo_unlink(loid) FROM lotest_stash_values;
--- 391,407 ----
(1 row)
\lo_unlink :newloid
+ \lo_import 'results/lotest.txt'
+ \set newloid_1 :LASTOID
+ SELECT make_lo(load_lo(:newloid_1)) AS newloid_2
+ \gset
+ SELECT md5(load_lo(:newloid_1)) = md5(load_lo(:newloid_2));
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ \lo_unlink :newloid_1
+ \lo_unlink :newloid_2
TRUNCATE lotest_stash_values;
DROP ROLE regresslo;