mirror of https://github.com/postgres/postgres
Adjust lo_open() so that specifying INV_READ without INV_WRITE creates
a descriptor that uses the current transaction snapshot, rather than SnapshotNow as it did before (and still does if INV_WRITE is set). This means pg_dump will now dump a consistent snapshot of large object contents, as it never could do before. Also, add a lo_create() function that is similar to lo_creat() but allows the desired OID of the large object to be specified. This will simplify pg_restore considerably (but I'll fix that in a separate commit).
This commit is contained in:
parent
f52a34229b
commit
a2fb7b8a1f
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/lobj.sgml,v 1.36 2005/01/10 00:04:38 tgl Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/lobj.sgml,v 1.37 2005/06/13 02:26:46 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="largeObjects">
|
||||
|
@ -115,26 +115,52 @@ $PostgreSQL: pgsql/doc/src/sgml/lobj.sgml,v 1.36 2005/01/10 00:04:38 tgl Exp $
|
|||
Oid lo_creat(PGconn *conn, int mode);
|
||||
</synopsis>
|
||||
<indexterm><primary>lo_creat</></>
|
||||
creates a new large object.
|
||||
<replaceable class="parameter">mode</replaceable> is a bit mask
|
||||
describing several different attributes of the new
|
||||
object. The symbolic constants used here are defined
|
||||
in the header file <filename>libpq/libpq-fs.h</filename>.
|
||||
The access type (read, write, or both) is controlled by
|
||||
or'ing together the bits <symbol>INV_READ</symbol> and
|
||||
<symbol>INV_WRITE</symbol>. The low-order sixteen bits of the mask have
|
||||
historically been used at Berkeley to designate the storage manager number on which the large object
|
||||
should reside. These bits should always be zero now. (The access type
|
||||
does not actually do anything anymore either, but one or both flag bits
|
||||
must be set to avoid an error.)
|
||||
creates a new large object.
|
||||
The return value is the OID that was assigned to the new large object,
|
||||
or InvalidOid (zero) on failure.
|
||||
|
||||
<replaceable class="parameter">mode</replaceable> is unused and
|
||||
ignored as of <productname>PostgreSQL</productname> 8.1; however, for
|
||||
backwards compatibility with earlier releases it is best to
|
||||
set it to <symbol>INV_READ</symbol>, <symbol>INV_WRITE</symbol>,
|
||||
or <symbol>INV_READ</symbol> <literal>|</> <symbol>INV_WRITE</symbol>.
|
||||
(These symbolic constants are defined
|
||||
in the header file <filename>libpq/libpq-fs.h</filename>.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An example:
|
||||
<programlisting>
|
||||
inv_oid = lo_creat(conn, INV_READ|INV_WRITE);
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The function
|
||||
<synopsis>
|
||||
Oid lo_create(PGconn *conn, Oid lobjId);
|
||||
</synopsis>
|
||||
<indexterm><primary>lo_create</></>
|
||||
also creates a new large object. The OID to be assigned can be
|
||||
specified by <replaceable class="parameter">lobjId</replaceable>;
|
||||
if so, failure occurs if that OID is already in use for some large
|
||||
object. If <replaceable class="parameter">lobjId</replaceable>
|
||||
is InvalidOid (zero) then <function>lo_create</> assigns an unused
|
||||
OID (this is the same behavior as <function>lo_creat</>).
|
||||
The return value is the OID that was assigned to the new large object,
|
||||
or InvalidOid (zero) on failure.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function>lo_create</> is new as of <productname>PostgreSQL</productname>
|
||||
8.1; if this function is run against an older server version, it will
|
||||
fail and return InvalidOid.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An example:
|
||||
<programlisting>
|
||||
inv_oid = lo_create(conn, desired_oid);
|
||||
</programlisting>
|
||||
</para>
|
||||
</sect2>
|
||||
|
@ -186,11 +212,13 @@ int lo_export(PGconn *conn, Oid lobjId, const char *filename);
|
|||
int lo_open(PGconn *conn, Oid lobjId, int mode);
|
||||
</synopsis>
|
||||
<indexterm><primary>lo_open</></>
|
||||
The <parameter>lobjId</parameter> argument specifies the OID of the large
|
||||
object to open. The <parameter>mode</parameter> bits control whether the
|
||||
object is opened for reading (<symbol>INV_READ</>), writing (<symbol>INV_WRITE</symbol>), or
|
||||
both.
|
||||
A large object cannot be opened before it is created.
|
||||
The <parameter>lobjId</parameter> argument specifies the OID of the large
|
||||
object to open. The <parameter>mode</parameter> bits control whether the
|
||||
object is opened for reading (<symbol>INV_READ</>), writing
|
||||
(<symbol>INV_WRITE</symbol>), or both.
|
||||
(These symbolic constants are defined
|
||||
in the header file <filename>libpq/libpq-fs.h</filename>.)
|
||||
A large object cannot be opened before it is created.
|
||||
<function>lo_open</function> returns a (non-negative) large object
|
||||
descriptor for later use in <function>lo_read</function>,
|
||||
<function>lo_write</function>, <function>lo_lseek</function>,
|
||||
|
@ -198,7 +226,31 @@ int lo_open(PGconn *conn, Oid lobjId, int mode);
|
|||
The descriptor is only valid for
|
||||
the duration of the current transaction.
|
||||
On failure, -1 is returned.
|
||||
</para>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The server currently does not distinguish between modes
|
||||
<symbol>INV_WRITE</symbol> and <symbol>INV_READ</> <literal>|</>
|
||||
<symbol>INV_WRITE</symbol>: you are allowed to read from the descriptor
|
||||
in either case. However there is a significant difference between
|
||||
these modes and <symbol>INV_READ</> alone: with <symbol>INV_READ</>
|
||||
you cannot write on the descriptor, and the data read from it will
|
||||
reflect the contents of the large object at the time of the transaction
|
||||
snapshot that was active when <function>lo_open</> was executed,
|
||||
regardless of later writes by this or other transactions. Reading
|
||||
from a descriptor opened with <symbol>INV_WRITE</symbol> returns
|
||||
data that reflects all writes of other committed transactions as well
|
||||
as writes of the current transaction. This is similar to the behavior
|
||||
of <literal>SERIALIZABLE</> versus <literal>READ COMMITTED</> transaction
|
||||
modes for ordinary SQL <command>SELECT</> commands.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An example:
|
||||
<programlisting>
|
||||
inv_fd = lo_open(conn, inv_oid, INV_READ|INV_WRITE);
|
||||
</programlisting>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
|
@ -317,6 +369,7 @@ int lo_unlink(PGconn *conn, Oid lobjId);
|
|||
equivalent server-side functions. The ones that are actually useful
|
||||
to call via SQL commands are
|
||||
<function>lo_creat</function><indexterm><primary>lo_creat</></>,
|
||||
<function>lo_create</function><indexterm><primary>lo_create</></>,
|
||||
<function>lo_unlink</function><indexterm><primary>lo_unlink</></>,
|
||||
<function>lo_import</function><indexterm><primary>lo_import</></>, and
|
||||
<function>lo_export</function><indexterm><primary>lo_export</></>.
|
||||
|
@ -330,6 +383,8 @@ CREATE TABLE image (
|
|||
|
||||
SELECT lo_creat(-1); -- returns OID of new, empty large object
|
||||
|
||||
SELECT lo_create(43213); -- attempts to create large object with OID 43213
|
||||
|
||||
SELECT lo_unlink(173454); -- deletes large object with OID 173454
|
||||
|
||||
INSERT INTO image (name, raster)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/be-fsstubs.c,v 1.77 2004/12/31 21:59:50 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/be-fsstubs.c,v 1.78 2005/06/13 02:26:48 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This should be moved to a more appropriate place. It is here
|
||||
|
@ -195,6 +195,12 @@ lo_write(int fd, char *buf, int len)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((cookies[fd]->flags & IFS_WRLOCK) == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("large object descriptor %d was not opened for writing",
|
||||
fd)));
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
|
@ -236,26 +242,33 @@ lo_lseek(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
lo_creat(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 mode = PG_GETARG_INT32(0);
|
||||
LargeObjectDesc *lobjDesc;
|
||||
MemoryContext currentContext;
|
||||
Oid lobjId;
|
||||
MemoryContext currentContext;
|
||||
|
||||
/* do we actually need fscxt for this? */
|
||||
CreateFSContext();
|
||||
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
lobjDesc = inv_create(mode);
|
||||
lobjId = inv_create(InvalidOid);
|
||||
|
||||
if (lobjDesc == NULL)
|
||||
{
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
PG_RETURN_OID(InvalidOid);
|
||||
}
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
lobjId = lobjDesc->id;
|
||||
PG_RETURN_OID(lobjId);
|
||||
}
|
||||
|
||||
inv_close(lobjDesc);
|
||||
Datum
|
||||
lo_create(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid lobjId = PG_GETARG_OID(0);
|
||||
MemoryContext currentContext;
|
||||
|
||||
/* do we actually need fscxt for this? */
|
||||
CreateFSContext();
|
||||
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
lobjId = inv_create(lobjId);
|
||||
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
|
@ -403,12 +416,13 @@ lo_import(PG_FUNCTION_ARGS)
|
|||
/*
|
||||
* create an inversion object
|
||||
*/
|
||||
lobj = inv_create(INV_READ | INV_WRITE);
|
||||
lobjOid = lobj->id;
|
||||
lobjOid = inv_create(InvalidOid);
|
||||
|
||||
/*
|
||||
* read in from the filesystem and write to the inversion file
|
||||
* read in from the filesystem and write to the inversion object
|
||||
*/
|
||||
lobj = inv_open(lobjOid, INV_WRITE);
|
||||
|
||||
while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0)
|
||||
{
|
||||
tmp = inv_write(lobj, buf, nbytes);
|
||||
|
@ -421,8 +435,8 @@ lo_import(PG_FUNCTION_ARGS)
|
|||
errmsg("could not read server file \"%s\": %m",
|
||||
fnamebuf)));
|
||||
|
||||
FileClose(fd);
|
||||
inv_close(lobj);
|
||||
FileClose(fd);
|
||||
|
||||
PG_RETURN_OID(lobjOid);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.110 2005/04/14 20:03:25 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.111 2005/06/13 02:26:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -114,6 +114,42 @@ close_lo_relation(bool isCommit)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Same as pg_largeobject.c's LargeObjectExists(), except snapshot to
|
||||
* read with can be specified.
|
||||
*/
|
||||
static bool
|
||||
myLargeObjectExists(Oid loid, Snapshot snapshot)
|
||||
{
|
||||
bool retval = false;
|
||||
Relation pg_largeobject;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc sd;
|
||||
|
||||
/*
|
||||
* See if we can find any tuples belonging to the specified LO
|
||||
*/
|
||||
ScanKeyInit(&skey[0],
|
||||
Anum_pg_largeobject_loid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(loid));
|
||||
|
||||
pg_largeobject = heap_open(LargeObjectRelationId, AccessShareLock);
|
||||
|
||||
sd = systable_beginscan(pg_largeobject, LargeObjectLOidPNIndexId, true,
|
||||
snapshot, 1, skey);
|
||||
|
||||
if (systable_getnext(sd) != NULL)
|
||||
retval = true;
|
||||
|
||||
systable_endscan(sd);
|
||||
|
||||
heap_close(pg_largeobject, AccessShareLock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
getbytealen(bytea *data)
|
||||
{
|
||||
|
@ -125,58 +161,44 @@ getbytealen(bytea *data)
|
|||
|
||||
|
||||
/*
|
||||
* inv_create -- create a new large object.
|
||||
* inv_create -- create a new large object
|
||||
*
|
||||
* Arguments:
|
||||
* flags
|
||||
* Arguments:
|
||||
* lobjId - OID to use for new large object, or InvalidOid to pick one
|
||||
*
|
||||
* Returns:
|
||||
* large object descriptor, appropriately filled in.
|
||||
* Returns:
|
||||
* OID of new object
|
||||
*
|
||||
* If lobjId is not InvalidOid, then an error occurs if the OID is already
|
||||
* in use.
|
||||
*/
|
||||
LargeObjectDesc *
|
||||
inv_create(int flags)
|
||||
Oid
|
||||
inv_create(Oid lobjId)
|
||||
{
|
||||
Oid file_oid;
|
||||
LargeObjectDesc *retval;
|
||||
|
||||
/*
|
||||
* Allocate an OID to be the LO's identifier.
|
||||
* Allocate an OID to be the LO's identifier, unless we were told
|
||||
* what to use. In event of collision with an existing ID, loop
|
||||
* to find a free one.
|
||||
*/
|
||||
file_oid = newoid();
|
||||
|
||||
/* Check for duplicate (shouldn't happen) */
|
||||
if (LargeObjectExists(file_oid))
|
||||
elog(ERROR, "large object %u already exists", file_oid);
|
||||
if (!OidIsValid(lobjId))
|
||||
{
|
||||
do {
|
||||
lobjId = newoid();
|
||||
} while (LargeObjectExists(lobjId));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the LO by writing an empty first page for it in
|
||||
* pg_largeobject
|
||||
* pg_largeobject (will fail if duplicate)
|
||||
*/
|
||||
LargeObjectCreate(file_oid);
|
||||
LargeObjectCreate(lobjId);
|
||||
|
||||
/*
|
||||
* Advance command counter so that new tuple will be seen by later
|
||||
* large-object operations in this transaction.
|
||||
* Advance command counter to make new tuple visible to later operations.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Prepare LargeObjectDesc data structure for accessing LO
|
||||
*/
|
||||
retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
|
||||
|
||||
retval->id = file_oid;
|
||||
retval->subid = GetCurrentSubTransactionId();
|
||||
retval->offset = 0;
|
||||
|
||||
if (flags & INV_WRITE)
|
||||
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
|
||||
else if (flags & INV_READ)
|
||||
retval->flags = IFS_RDLOCK;
|
||||
else
|
||||
elog(ERROR, "invalid flags: %d", flags);
|
||||
|
||||
return retval;
|
||||
return lobjId;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -190,11 +212,6 @@ inv_open(Oid lobjId, int flags)
|
|||
{
|
||||
LargeObjectDesc *retval;
|
||||
|
||||
if (!LargeObjectExists(lobjId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("large object %u does not exist", lobjId)));
|
||||
|
||||
retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
|
||||
|
||||
retval->id = lobjId;
|
||||
|
@ -202,12 +219,25 @@ inv_open(Oid lobjId, int flags)
|
|||
retval->offset = 0;
|
||||
|
||||
if (flags & INV_WRITE)
|
||||
{
|
||||
retval->snapshot = SnapshotNow;
|
||||
retval->flags = IFS_WRLOCK | IFS_RDLOCK;
|
||||
}
|
||||
else if (flags & INV_READ)
|
||||
{
|
||||
/* be sure to copy snap into fscxt */
|
||||
retval->snapshot = CopySnapshot(ActiveSnapshot);
|
||||
retval->flags = IFS_RDLOCK;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "invalid flags: %d", flags);
|
||||
|
||||
/* Can't use LargeObjectExists here because it always uses SnapshotNow */
|
||||
if (!myLargeObjectExists(lobjId, retval->snapshot))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("large object %u does not exist", lobjId)));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -218,6 +248,8 @@ void
|
|||
inv_close(LargeObjectDesc *obj_desc)
|
||||
{
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
if (obj_desc->snapshot != SnapshotNow)
|
||||
FreeSnapshot(obj_desc->snapshot);
|
||||
pfree(obj_desc);
|
||||
}
|
||||
|
||||
|
@ -268,7 +300,7 @@ inv_getsize(LargeObjectDesc *obj_desc)
|
|||
ObjectIdGetDatum(obj_desc->id));
|
||||
|
||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
||||
SnapshotNow, 1, skey);
|
||||
obj_desc->snapshot, 1, skey);
|
||||
|
||||
/*
|
||||
* Because the pg_largeobject index is on both loid and pageno, but we
|
||||
|
@ -379,7 +411,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||
Int32GetDatum(pageno));
|
||||
|
||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
||||
SnapshotNow, 2, skey);
|
||||
obj_desc->snapshot, 2, skey);
|
||||
|
||||
while ((tuple = index_getnext(sd, ForwardScanDirection)) != NULL)
|
||||
{
|
||||
|
@ -470,6 +502,13 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||
Assert(PointerIsValid(obj_desc));
|
||||
Assert(buf != NULL);
|
||||
|
||||
/* enforce writability because snapshot is probably wrong otherwise */
|
||||
if ((obj_desc->flags & IFS_WRLOCK) == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("large object %u was not opened for writing",
|
||||
obj_desc->id)));
|
||||
|
||||
if (nbytes <= 0)
|
||||
return 0;
|
||||
|
||||
|
@ -488,7 +527,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
|||
Int32GetDatum(pageno));
|
||||
|
||||
sd = index_beginscan(lo_heap_r, lo_index_r,
|
||||
SnapshotNow, 2, skey);
|
||||
obj_desc->snapshot, 2, skey);
|
||||
|
||||
oldtuple = NULL;
|
||||
olddata = NULL;
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.273 2005/06/07 07:08:34 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.274 2005/06/13 02:26:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200506071
|
||||
#define CATALOG_VERSION_NO 200506121
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.365 2005/06/09 16:35:09 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.366 2005/06/13 02:26:50 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
|
@ -1248,6 +1248,8 @@ DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 f f t f v 3 23 "23 23 23" _
|
|||
DESCR("large object seek");
|
||||
DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 f f t f v 1 26 "23" _null_ _null_ _null_ lo_creat - _null_ ));
|
||||
DESCR("large object create");
|
||||
DATA(insert OID = 715 ( lo_create PGNSP PGUID 12 f f t f v 1 26 "26" _null_ _null_ _null_ lo_create - _null_ ));
|
||||
DESCR("large object create");
|
||||
DATA(insert OID = 958 ( lo_tell PGNSP PGUID 12 f f t f v 1 23 "23" _null_ _null_ _null_ lo_tell - _null_ ));
|
||||
DESCR("large object position");
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/libpq/be-fsstubs.h,v 1.23 2004/12/31 22:03:32 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/include/libpq/be-fsstubs.h,v 1.24 2005/06/13 02:26:51 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -23,6 +23,7 @@ extern Datum lo_import(PG_FUNCTION_ARGS);
|
|||
extern Datum lo_export(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum lo_creat(PG_FUNCTION_ARGS);
|
||||
extern Datum lo_create(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum lo_open(PG_FUNCTION_ARGS);
|
||||
extern Datum lo_close(PG_FUNCTION_ARGS);
|
||||
|
|
|
@ -8,19 +8,22 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/storage/large_object.h,v 1.31 2004/12/31 22:03:42 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/include/storage/large_object.h,v 1.32 2005/06/13 02:26:52 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef LARGE_OBJECT_H
|
||||
#define LARGE_OBJECT_H
|
||||
|
||||
#include "utils/tqual.h"
|
||||
|
||||
|
||||
/*----------
|
||||
* Data about a currently-open large object.
|
||||
*
|
||||
* id is the logical OID of the large object
|
||||
* subid is the subtransaction that opened the LO (or currently owns it)
|
||||
* snapshot is the snapshot to use for read/write operations
|
||||
* subid is the subtransaction that opened the desc (or currently owns it)
|
||||
* offset is the current seek offset within the LO
|
||||
* flags contains some flag bits
|
||||
*
|
||||
|
@ -32,6 +35,7 @@
|
|||
typedef struct LargeObjectDesc
|
||||
{
|
||||
Oid id; /* LO's identifier */
|
||||
Snapshot snapshot; /* snapshot to use */
|
||||
SubTransactionId subid; /* owning subtransaction ID */
|
||||
uint32 offset; /* current seek pointer */
|
||||
int flags; /* locking info, etc */
|
||||
|
@ -39,6 +43,7 @@ typedef struct LargeObjectDesc
|
|||
/* flag bits: */
|
||||
#define IFS_RDLOCK (1 << 0)
|
||||
#define IFS_WRLOCK (1 << 1)
|
||||
|
||||
} LargeObjectDesc;
|
||||
|
||||
|
||||
|
@ -65,7 +70,7 @@ typedef struct LargeObjectDesc
|
|||
|
||||
/* inversion stuff in inv_api.c */
|
||||
extern void close_lo_relation(bool isCommit);
|
||||
extern LargeObjectDesc *inv_create(int flags);
|
||||
extern Oid inv_create(Oid lobjId);
|
||||
extern LargeObjectDesc *inv_open(Oid lobjId, int flags);
|
||||
extern void inv_close(LargeObjectDesc *obj_desc);
|
||||
extern int inv_drop(Oid lobjId);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.3 2004/10/30 23:11:26 tgl Exp $
|
||||
# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.4 2005/06/13 02:26:53 tgl Exp $
|
||||
# Functions to be exported by libpq DLLs
|
||||
PQconnectdb 1
|
||||
PQsetdbLogin 2
|
||||
|
@ -122,3 +122,4 @@ PQsendPrepare 119
|
|||
PQgetCancel 120
|
||||
PQfreeCancel 121
|
||||
PQcancel 122
|
||||
lo_create 123
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-lobj.c,v 1.52 2004/12/31 22:03:50 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-lobj.c,v 1.53 2005/06/13 02:26:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -266,12 +266,11 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
|
|||
/*
|
||||
* lo_creat
|
||||
* create a new large object
|
||||
* the mode is a bitmask describing different attributes of the new object
|
||||
* the mode is ignored (once upon a time it had a use)
|
||||
*
|
||||
* returns the oid of the large object created or
|
||||
* InvalidOid upon failure
|
||||
*/
|
||||
|
||||
Oid
|
||||
lo_creat(PGconn *conn, int mode)
|
||||
{
|
||||
|
@ -303,6 +302,53 @@ lo_creat(PGconn *conn, int mode)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* lo_create
|
||||
* create a new large object
|
||||
* if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create
|
||||
*
|
||||
* returns the oid of the large object created or
|
||||
* InvalidOid upon failure
|
||||
*/
|
||||
Oid
|
||||
lo_create(PGconn *conn, Oid lobjId)
|
||||
{
|
||||
PQArgBlock argv[1];
|
||||
PGresult *res;
|
||||
int retval;
|
||||
int result_len;
|
||||
|
||||
if (conn->lobjfuncs == NULL)
|
||||
{
|
||||
if (lo_initialize(conn) < 0)
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
/* Must check this on-the-fly because it's not there pre-8.1 */
|
||||
if (conn->lobjfuncs->fn_lo_create == 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("cannot determine OID of function lo_create\n"));
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
argv[0].isint = 1;
|
||||
argv[0].len = 4;
|
||||
argv[0].u.integer = lobjId;
|
||||
res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
|
||||
&retval, &result_len, 1, argv, 1);
|
||||
if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
PQclear(res);
|
||||
return (Oid) retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
PQclear(res);
|
||||
return InvalidOid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* lo_tell
|
||||
|
@ -560,7 +606,8 @@ lo_initialize(PGconn *conn)
|
|||
|
||||
/*
|
||||
* Execute the query to get all the functions at once. In 7.3 and
|
||||
* later we need to be schema-safe.
|
||||
* later we need to be schema-safe. lo_create only exists in 8.1
|
||||
* and up.
|
||||
*/
|
||||
if (conn->sversion >= 70300)
|
||||
query = "select proname, oid from pg_catalog.pg_proc "
|
||||
|
@ -568,6 +615,7 @@ lo_initialize(PGconn *conn)
|
|||
"'lo_open', "
|
||||
"'lo_close', "
|
||||
"'lo_creat', "
|
||||
"'lo_create', "
|
||||
"'lo_unlink', "
|
||||
"'lo_lseek', "
|
||||
"'lo_tell', "
|
||||
|
@ -615,6 +663,8 @@ lo_initialize(PGconn *conn)
|
|||
lobjfuncs->fn_lo_close = foid;
|
||||
else if (!strcmp(fname, "lo_creat"))
|
||||
lobjfuncs->fn_lo_creat = foid;
|
||||
else if (!strcmp(fname, "lo_create"))
|
||||
lobjfuncs->fn_lo_create = foid;
|
||||
else if (!strcmp(fname, "lo_unlink"))
|
||||
lobjfuncs->fn_lo_unlink = foid;
|
||||
else if (!strcmp(fname, "lo_lseek"))
|
||||
|
@ -631,7 +681,7 @@ lo_initialize(PGconn *conn)
|
|||
|
||||
/*
|
||||
* Finally check that we really got all large object interface
|
||||
* functions.
|
||||
* functions --- except lo_create, which may not exist.
|
||||
*/
|
||||
if (lobjfuncs->fn_lo_open == 0)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.117 2005/06/09 20:01:16 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.118 2005/06/13 02:26:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -480,6 +480,7 @@ extern int lo_read(PGconn *conn, int fd, char *buf, size_t len);
|
|||
extern int lo_write(PGconn *conn, int fd, char *buf, size_t len);
|
||||
extern int lo_lseek(PGconn *conn, int fd, int offset, int whence);
|
||||
extern Oid lo_creat(PGconn *conn, int mode);
|
||||
extern Oid lo_create(PGconn *conn, Oid lobjId);
|
||||
extern int lo_tell(PGconn *conn, int fd);
|
||||
extern int lo_unlink(PGconn *conn, Oid lobjId);
|
||||
extern Oid lo_import(PGconn *conn, const char *filename);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.102 2005/06/12 00:00:21 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.103 2005/06/13 02:26:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -229,6 +229,7 @@ typedef struct pgLobjfuncs
|
|||
Oid fn_lo_open; /* OID of backend function lo_open */
|
||||
Oid fn_lo_close; /* OID of backend function lo_close */
|
||||
Oid fn_lo_creat; /* OID of backend function lo_creat */
|
||||
Oid fn_lo_create; /* OID of backend function lo_create */
|
||||
Oid fn_lo_unlink; /* OID of backend function lo_unlink */
|
||||
Oid fn_lo_lseek; /* OID of backend function lo_lseek */
|
||||
Oid fn_lo_tell; /* OID of backend function lo_tell */
|
||||
|
|
Loading…
Reference in New Issue