]> granicus.if.org Git - postgresql/commitdiff
Adjust lo_open() so that specifying INV_READ without INV_WRITE creates
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Jun 2005 02:26:53 +0000 (02:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Jun 2005 02:26:53 +0000 (02:26 +0000)
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).

doc/src/sgml/lobj.sgml
src/backend/libpq/be-fsstubs.c
src/backend/storage/large_object/inv_api.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/libpq/be-fsstubs.h
src/include/storage/large_object.h
src/interfaces/libpq/exports.txt
src/interfaces/libpq/fe-lobj.c
src/interfaces/libpq/libpq-fe.h
src/interfaces/libpq/libpq-int.h

index 82ca839efb2616394b07f5885c6b32ac7eec8fab..98516082c971bbc18e73c3e79e1c6733f2d225fa 100644 (file)
@@ -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)
index f600e140e785281d89b087ded3dd4d4e0418aea4..016884e425f7f4ba6982be6332a3b60af3e42c87 100644 (file)
@@ -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);
+
+       PG_RETURN_OID(lobjId);
+}
+
+Datum
+lo_create(PG_FUNCTION_ARGS)
+{
+       Oid                     lobjId = PG_GETARG_OID(0);
+       MemoryContext currentContext;
 
-       lobjId = lobjDesc->id;
+       /* do we actually need fscxt for this? */
+       CreateFSContext();
+
+       currentContext = MemoryContextSwitchTo(fscxt);
 
-       inv_close(lobjDesc);
+       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);
 }
index 299e0756d1f92b8909c73652af59a8b80aed7123..38734a5f9c37cae2e6f873d03fcf629571366b57 100644 (file)
@@ -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;
index a58ec7b5a57c0a64119d266b2a09156cae253351..ee8b3aee0a28787982dd8c31a6a55c097b83c90a 100644 (file)
@@ -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
index 5bf7753dcea661f1f0b0d1da31a9856963f0d269..bc5d8afefaf266c349a2468e695daf14056f47c9 100644 (file)
@@ -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");
 
index 0e40374e7d3ab8e5b2b6b57373923aad829f0a9b..1307293b2570a048368a8ae000fb5c7a98f904b5 100644 (file)
@@ -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);
index 758fb6f039834e91cb2789139fd8fe14c9829eab..c9795d2f7a31f77d105e53990fba4762a30819a1 100644 (file)
@@ -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);
index 363764fffe9cc7452c9879649663e85004eec96f..8d0c4b9743ca0af4d98d5ddd282639468f01f0b6 100644 (file)
@@ -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
index 30c77e98a539265d354cda0c806176d31eeb2205..665efe90bc9f52b68576ad8c7f98a2baaa6cbc37 100644 (file)
@@ -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)
        {
index 8976d45e2583a11385946928cbbbf397d48b1bad..56fba44f8bb4a45ff27f6aac33a0aaa8697ddea6 100644 (file)
@@ -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);
index 6e14fa8df25ca3399efb33ea33813d91eef2f755..2274efbfb546ee766ee4d8598972b44839c9a5fb 100644 (file)
@@ -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              */