2010-09-20 22:08:53 +02:00
|
|
|
<!-- doc/src/sgml/lobj.sgml -->
|
2000-03-31 05:27:42 +02:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<chapter id="largeObjects">
|
2010-04-03 09:23:02 +02:00
|
|
|
<title>Large Objects</title>
|
1999-06-14 09:36:12 +02:00
|
|
|
|
2001-11-12 20:19:39 +01:00
|
|
|
<indexterm zone="largeobjects"><primary>large object</></>
|
|
|
|
<indexterm><primary>BLOB</><see>large object</></>
|
|
|
|
|
1999-10-04 17:18:54 +02:00
|
|
|
<para>
|
2004-12-28 23:47:15 +01:00
|
|
|
<productname>PostgreSQL</productname> has a <firstterm>large object</>
|
|
|
|
facility, which provides stream-style access to user data that is stored
|
|
|
|
in a special large-object structure. Streaming access is useful
|
|
|
|
when working with data values that are too large to manipulate
|
|
|
|
conveniently as a whole.
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
2001-09-17 00:53:52 +02:00
|
|
|
|
2003-03-13 02:30:29 +01:00
|
|
|
<para>
|
|
|
|
This chapter describes the implementation and the programming and
|
|
|
|
query language interfaces to <productname>PostgreSQL</productname>
|
|
|
|
large object data. We use the <application>libpq</application> C
|
|
|
|
library for the examples in this chapter, but most programming
|
|
|
|
interfaces native to <productname>PostgreSQL</productname> support
|
Update documentation on may/can/might:
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
Also update two error messages mentioned in the documenation to match.
2007-01-31 21:56:20 +01:00
|
|
|
equivalent functionality. Other interfaces might use the large
|
2003-03-13 02:30:29 +01:00
|
|
|
object interface internally to provide generic support for large
|
|
|
|
values. This is not described here.
|
|
|
|
</para>
|
|
|
|
|
2006-04-23 05:39:52 +02:00
|
|
|
<sect1 id="lo-intro">
|
|
|
|
<title>Introduction</title>
|
2003-03-13 02:30:29 +01:00
|
|
|
|
2006-04-23 05:39:52 +02:00
|
|
|
<indexterm>
|
|
|
|
<primary>TOAST</primary>
|
|
|
|
<secondary>versus large objects</secondary>
|
|
|
|
</indexterm>
|
2001-09-17 00:53:52 +02:00
|
|
|
|
|
|
|
<para>
|
2006-04-23 05:39:52 +02:00
|
|
|
All large objects are placed in a single system table called
|
|
|
|
<classname>pg_largeobject</classname>.
|
|
|
|
<productname>PostgreSQL</productname> also supports a storage system called
|
|
|
|
<quote><acronym>TOAST</acronym></quote> that automatically stores values
|
|
|
|
larger than a single database page into a secondary storage area per table.
|
|
|
|
This makes the large object facility partially obsolete. One
|
2004-12-28 23:47:15 +01:00
|
|
|
remaining advantage of the large object facility is that it allows values
|
|
|
|
up to 2 GB in size, whereas <acronym>TOAST</acronym>ed fields can be at
|
2010-11-23 21:27:50 +01:00
|
|
|
most 1 GB. Also, large objects can be randomly modified using a read/write
|
2006-04-23 05:39:52 +02:00
|
|
|
API that is more efficient than performing such operations using
|
|
|
|
<acronym>TOAST</acronym>.
|
2001-09-17 00:53:52 +02:00
|
|
|
</para>
|
|
|
|
|
1999-10-04 17:18:54 +02:00
|
|
|
</sect1>
|
|
|
|
|
2000-09-29 22:21:34 +02:00
|
|
|
<sect1 id="lo-implementation">
|
1999-10-04 17:18:54 +02:00
|
|
|
<title>Implementation Features</title>
|
|
|
|
|
|
|
|
<para>
|
2006-04-23 05:39:52 +02:00
|
|
|
The large object implementation breaks large
|
|
|
|
objects up into <quote>chunks</quote> and stores the chunks in
|
2003-03-13 02:30:29 +01:00
|
|
|
rows in the database. A B-tree index guarantees fast
|
1999-10-04 17:18:54 +02:00
|
|
|
searches for the correct chunk number when doing random
|
|
|
|
access reads and writes.
|
|
|
|
</para>
|
2009-12-17 15:36:16 +01:00
|
|
|
|
|
|
|
<para>
|
2010-02-17 05:19:41 +01:00
|
|
|
As of <productname>PostgreSQL</> 9.0, large objects have an owner
|
2009-12-17 15:36:16 +01:00
|
|
|
and a set of access permissions, which can be managed using
|
2010-04-03 09:23:02 +02:00
|
|
|
<xref linkend="sql-grant"> and
|
2010-11-23 21:27:50 +01:00
|
|
|
<xref linkend="sql-revoke">.
|
2009-12-17 15:36:16 +01:00
|
|
|
For compatibility with prior releases, see
|
|
|
|
<xref linkend="guc-lo-compat-privileges">.
|
|
|
|
<literal>SELECT</literal> privileges are required to read a large
|
2010-11-23 21:27:50 +01:00
|
|
|
object, and
|
2009-12-17 15:36:16 +01:00
|
|
|
<literal>UPDATE</literal> privileges are required to write to or
|
|
|
|
truncate it.
|
|
|
|
Only the large object owner (or the database superuser) can unlink, comment
|
|
|
|
on, or change the owner of a large object.
|
|
|
|
</para>
|
1999-10-04 17:18:54 +02:00
|
|
|
</sect1>
|
|
|
|
|
2000-09-29 22:21:34 +02:00
|
|
|
<sect1 id="lo-interfaces">
|
2003-03-13 02:30:29 +01:00
|
|
|
<title>Client Interfaces</title>
|
1999-10-04 17:18:54 +02:00
|
|
|
|
|
|
|
<para>
|
2003-03-13 02:30:29 +01:00
|
|
|
This section describes the facilities that
|
|
|
|
<productname>PostgreSQL</productname> client interface libraries
|
|
|
|
provide for accessing large objects. All large object
|
|
|
|
manipulation using these functions <emphasis>must</emphasis> take
|
2006-04-23 05:39:52 +02:00
|
|
|
place within an SQL transaction block.
|
2003-03-13 02:30:29 +01:00
|
|
|
The <productname>PostgreSQL</productname> large object interface is modeled after
|
|
|
|
the <acronym>Unix</acronym> file-system interface, with analogues of
|
|
|
|
<function>open</function>, <function>read</function>,
|
|
|
|
<function>write</function>,
|
|
|
|
<function>lseek</function>, etc.
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2003-03-13 02:30:29 +01:00
|
|
|
Client applications which use the large object interface in
|
|
|
|
<application>libpq</application> should include the header file
|
|
|
|
<filename>libpq/libpq-fs.h</filename> and link with the
|
|
|
|
<application>libpq</application> library.
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
|
|
|
|
2010-08-10 04:56:46 +02:00
|
|
|
<sect2 id="lo-create">
|
1999-10-04 17:18:54 +02:00
|
|
|
<title>Creating a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
2003-03-13 02:30:29 +01:00
|
|
|
The function
|
1999-11-11 22:52:28 +01:00
|
|
|
<synopsis>
|
2003-03-13 02:30:29 +01:00
|
|
|
Oid lo_creat(PGconn *conn, int mode);
|
1999-11-11 22:52:28 +01:00
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_creat</></>
|
2010-11-23 21:27:50 +01:00
|
|
|
creates a new large object.
|
2005-01-08 23:13:38 +01:00
|
|
|
The return value is the OID that was assigned to the new large object,
|
2006-10-23 20:10:32 +02:00
|
|
|
or <symbol>InvalidOid</symbol> (zero) on failure.
|
2005-06-13 04:26:53 +02:00
|
|
|
|
|
|
|
<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>.)
|
2003-03-13 02:30:29 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
An example:
|
2001-09-17 00:53:52 +02:00
|
|
|
<programlisting>
|
2005-01-08 23:13:38 +01:00
|
|
|
inv_oid = lo_creat(conn, INV_READ|INV_WRITE);
|
2005-06-13 04:26:53 +02:00
|
|
|
</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>
|
2006-10-23 20:10:32 +02:00
|
|
|
is <symbol>InvalidOid</symbol> (zero) then <function>lo_create</> assigns an unused
|
2005-06-13 04:26:53 +02:00
|
|
|
OID (this is the same behavior as <function>lo_creat</>).
|
|
|
|
The return value is the OID that was assigned to the new large object,
|
2006-10-23 20:10:32 +02:00
|
|
|
or <symbol>InvalidOid</symbol> (zero) on failure.
|
2005-06-13 04:26:53 +02:00
|
|
|
</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
|
2006-10-23 20:10:32 +02:00
|
|
|
fail and return <symbol>InvalidOid</symbol>.
|
2005-06-13 04:26:53 +02:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
An example:
|
|
|
|
<programlisting>
|
|
|
|
inv_oid = lo_create(conn, desired_oid);
|
2001-09-17 00:53:52 +02:00
|
|
|
</programlisting>
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-import">
|
1999-10-04 17:18:54 +02:00
|
|
|
<title>Importing a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
2002-01-07 03:29:15 +01:00
|
|
|
To import an operating system file as a large object, call
|
1999-11-11 22:52:28 +01:00
|
|
|
<synopsis>
|
2003-03-13 02:30:29 +01:00
|
|
|
Oid lo_import(PGconn *conn, const char *filename);
|
1999-11-11 22:52:28 +01:00
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_import</></>
|
2010-11-23 21:27:50 +01:00
|
|
|
<replaceable class="parameter">filename</replaceable>
|
2002-01-07 03:29:15 +01:00
|
|
|
specifies the operating system name of
|
1998-03-01 09:16:16 +01:00
|
|
|
the file to be imported as a large object.
|
2005-01-08 23:13:38 +01:00
|
|
|
The return value is the OID that was assigned to the new large object,
|
2006-10-23 20:10:32 +02:00
|
|
|
or <symbol>InvalidOid</symbol> (zero) on failure.
|
2004-12-28 23:47:15 +01:00
|
|
|
Note that the file is read by the client interface library, not by
|
2006-10-23 20:10:32 +02:00
|
|
|
the server; so it must exist in the client file system and be readable
|
2004-12-28 23:47:15 +01:00
|
|
|
by the client application.
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
2008-03-19 01:39:33 +01:00
|
|
|
|
|
|
|
<para>
|
|
|
|
The function
|
|
|
|
<synopsis>
|
|
|
|
Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
|
|
|
|
</synopsis>
|
|
|
|
<indexterm><primary>lo_import_with_oid</></>
|
|
|
|
also imports 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 <symbol>InvalidOid</symbol> (zero) then <function>lo_import_with_oid</> assigns an unused
|
|
|
|
OID (this is the same behavior as <function>lo_import</>).
|
|
|
|
The return value is the OID that was assigned to the new large object,
|
|
|
|
or <symbol>InvalidOid</symbol> (zero) on failure.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<function>lo_import_with_oid</> is new as of <productname>PostgreSQL</productname>
|
|
|
|
8.4 and uses <function>lo_create</function> internally which is new in 8.1; if this function is run against 8.0 or before, it will
|
|
|
|
fail and return <symbol>InvalidOid</symbol>.
|
|
|
|
</para>
|
1999-10-04 17:18:54 +02:00
|
|
|
</sect2>
|
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-export">
|
1999-10-04 17:18:54 +02:00
|
|
|
<title>Exporting a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
To export a large object
|
2002-01-07 03:29:15 +01:00
|
|
|
into an operating system file, call
|
1999-11-11 22:52:28 +01:00
|
|
|
<synopsis>
|
2003-03-13 02:30:29 +01:00
|
|
|
int lo_export(PGconn *conn, Oid lobjId, const char *filename);
|
1999-11-11 22:52:28 +01:00
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_export</></>
|
2005-01-08 23:13:38 +01:00
|
|
|
The <parameter>lobjId</parameter> argument specifies the OID of the large
|
|
|
|
object to export and the <parameter>filename</parameter> argument
|
|
|
|
specifies the operating system name of the file. Note that the file is
|
|
|
|
written by the client interface library, not by the server. Returns 1
|
|
|
|
on success, -1 on failure.
|
1999-10-04 17:18:54 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-open">
|
1999-10-04 17:18:54 +02:00
|
|
|
<title>Opening an Existing Large Object</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
1999-10-04 17:18:54 +02:00
|
|
|
<para>
|
2005-01-08 23:13:38 +01:00
|
|
|
To open an existing large object for reading or writing, call
|
1999-11-11 22:52:28 +01:00
|
|
|
<synopsis>
|
2003-03-13 02:30:29 +01:00
|
|
|
int lo_open(PGconn *conn, Oid lobjId, int mode);
|
1999-11-11 22:52:28 +01:00
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_open</></>
|
2005-06-13 04:26:53 +02:00
|
|
|
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.
|
2005-01-08 23:13:38 +01:00
|
|
|
<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>,
|
|
|
|
<function>lo_tell</function>, and <function>lo_close</function>.
|
2010-11-23 21:27:50 +01:00
|
|
|
The descriptor is only valid for
|
2003-06-21 23:51:35 +02:00
|
|
|
the duration of the current transaction.
|
2005-01-08 23:13:38 +01:00
|
|
|
On failure, -1 is returned.
|
2005-06-13 04:26:53 +02:00
|
|
|
</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
|
Implement genuine serializable isolation level.
Until now, our Serializable mode has in fact been what's called Snapshot
Isolation, which allows some anomalies that could not occur in any
serialized ordering of the transactions. This patch fixes that using a
method called Serializable Snapshot Isolation, based on research papers by
Michael J. Cahill (see README-SSI for full references). In Serializable
Snapshot Isolation, transactions run like they do in Snapshot Isolation,
but a predicate lock manager observes the reads and writes performed and
aborts transactions if it detects that an anomaly might occur. This method
produces some false positives, ie. it sometimes aborts transactions even
though there is no anomaly.
To track reads we implement predicate locking, see storage/lmgr/predicate.c.
Whenever a tuple is read, a predicate lock is acquired on the tuple. Shared
memory is finite, so when a transaction takes many tuple-level locks on a
page, the locks are promoted to a single page-level lock, and further to a
single relation level lock if necessary. To lock key values with no matching
tuple, a sequential scan always takes a relation-level lock, and an index
scan acquires a page-level lock that covers the search key, whether or not
there are any matching keys at the moment.
A predicate lock doesn't conflict with any regular locks or with another
predicate locks in the normal sense. They're only used by the predicate lock
manager to detect the danger of anomalies. Only serializable transactions
participate in predicate locking, so there should be no extra overhead for
for other transactions.
Predicate locks can't be released at commit, but must be remembered until
all the transactions that overlapped with it have completed. That means that
we need to remember an unbounded amount of predicate locks, so we apply a
lossy but conservative method of tracking locks for committed transactions.
If we run short of shared memory, we overflow to a new "pg_serial" SLRU
pool.
We don't currently allow Serializable transactions in Hot Standby mode.
That would be hard, because even read-only transactions can cause anomalies
that wouldn't otherwise occur.
Serializable isolation mode now means the new fully serializable level.
Repeatable Read gives you the old Snapshot Isolation level that we have
always had.
Kevin Grittner and Dan Ports, reviewed by Jeff Davis, Heikki Linnakangas and
Anssi Kääriäinen
2011-02-07 22:46:51 +01:00
|
|
|
of <literal>REPEATABLE READ</> versus <literal>READ COMMITTED</> transaction
|
2005-06-13 04:26:53 +02:00
|
|
|
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>
|
1999-06-14 09:36:12 +02:00
|
|
|
</sect2>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-write">
|
1999-06-14 09:36:12 +02:00
|
|
|
<title>Writing Data to a Large Object</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<para>
|
2003-03-13 02:30:29 +01:00
|
|
|
The function
|
|
|
|
<synopsis>
|
|
|
|
int lo_write(PGconn *conn, int fd, const char *buf, size_t len);
|
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_write</></> writes
|
|
|
|
<parameter>len</parameter> bytes from <parameter>buf</parameter>
|
2004-12-28 23:47:15 +01:00
|
|
|
to large object descriptor <parameter>fd</>. The <parameter>fd</parameter>
|
2003-08-31 19:32:24 +02:00
|
|
|
argument must have been returned by a previous
|
|
|
|
<function>lo_open</function>. The number of bytes actually
|
|
|
|
written is returned. In the event of an error, the return value
|
|
|
|
is negative.
|
1999-06-14 09:36:12 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-read">
|
1999-11-11 22:52:28 +01:00
|
|
|
<title>Reading Data from a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
2003-03-13 02:30:29 +01:00
|
|
|
The function
|
|
|
|
<synopsis>
|
|
|
|
int lo_read(PGconn *conn, int fd, char *buf, size_t len);
|
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_read</></> reads
|
2004-12-28 23:47:15 +01:00
|
|
|
<parameter>len</parameter> bytes from large object descriptor
|
2003-08-31 19:32:24 +02:00
|
|
|
<parameter>fd</parameter> into <parameter>buf</parameter>. The
|
|
|
|
<parameter>fd</parameter> argument must have been returned by a
|
|
|
|
previous <function>lo_open</function>. The number of bytes
|
|
|
|
actually read is returned. In the event of an error, the return
|
|
|
|
value is negative.
|
1999-11-11 22:52:28 +01:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-seek">
|
2004-12-28 23:47:15 +01:00
|
|
|
<title>Seeking in a Large Object</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<para>
|
2004-12-28 23:47:15 +01:00
|
|
|
To change the current read or write location associated with a
|
|
|
|
large object descriptor, call
|
2003-03-13 02:30:29 +01:00
|
|
|
<synopsis>
|
|
|
|
int lo_lseek(PGconn *conn, int fd, int offset, int whence);
|
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_lseek</></> This function moves the
|
2004-12-28 23:47:15 +01:00
|
|
|
current location pointer for the large object descriptor identified by
|
2003-08-31 19:32:24 +02:00
|
|
|
<parameter>fd</> to the new location specified by
|
|
|
|
<parameter>offset</>. The valid values for <parameter>whence</>
|
|
|
|
are <symbol>SEEK_SET</> (seek from object start),
|
|
|
|
<symbol>SEEK_CUR</> (seek from current position), and
|
|
|
|
<symbol>SEEK_END</> (seek from object end). The return value is
|
2005-01-08 23:13:38 +01:00
|
|
|
the new location pointer, or -1 on error.
|
2003-03-13 02:30:29 +01:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-tell">
|
2003-03-13 02:30:29 +01:00
|
|
|
<title>Obtaining the Seek Position of a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
2004-12-28 23:47:15 +01:00
|
|
|
To obtain the current read or write location of a large object descriptor,
|
2003-03-13 02:30:29 +01:00
|
|
|
call
|
|
|
|
<synopsis>
|
|
|
|
int lo_tell(PGconn *conn, int fd);
|
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_tell</></> If there is an error, the
|
|
|
|
return value is negative.
|
1999-06-14 09:36:12 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-truncate">
|
2007-03-03 20:52:47 +01:00
|
|
|
<title>Truncating a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
To truncate a large object to a given length, call
|
|
|
|
<synopsis>
|
|
|
|
int lo_truncate(PGcon *conn, int fd, size_t len);
|
|
|
|
</synopsis>
|
|
|
|
<indexterm><primary>lo_truncate</></> truncates the large object
|
|
|
|
descriptor <parameter>fd</> to length <parameter>len</>. The
|
|
|
|
<parameter>fd</parameter> argument must have been returned by a
|
|
|
|
previous <function>lo_open</function>. If <parameter>len</> is
|
|
|
|
greater than the current large object length, the large object
|
|
|
|
is extended with null bytes ('\0').
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The file offset is not changed.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
On success <function>lo_truncate</function> returns
|
|
|
|
zero. On error, the return value is negative.
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
<function>lo_truncate</> is new as of <productname>PostgreSQL</productname>
|
|
|
|
8.3; if this function is run against an older server version, it will
|
|
|
|
fail and return a negative value.
|
|
|
|
</para>
|
2007-03-14 01:15:26 +01:00
|
|
|
</sect2>
|
2007-03-03 20:52:47 +01:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-close">
|
1999-06-14 09:36:12 +02:00
|
|
|
<title>Closing a Large Object Descriptor</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<para>
|
Update documentation on may/can/might:
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
Also update two error messages mentioned in the documenation to match.
2007-01-31 21:56:20 +01:00
|
|
|
A large object descriptor can be closed by calling
|
2003-03-13 02:30:29 +01:00
|
|
|
<synopsis>
|
|
|
|
int lo_close(PGconn *conn, int fd);
|
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_close</></> where <parameter>fd</> is a
|
|
|
|
large object descriptor returned by <function>lo_open</function>.
|
|
|
|
On success, <function>lo_close</function> returns zero. On
|
|
|
|
error, the return value is negative.
|
1999-06-14 09:36:12 +02:00
|
|
|
</para>
|
2003-06-21 23:51:35 +02:00
|
|
|
|
|
|
|
<para>
|
|
|
|
Any large object descriptors that remain open at the end of a
|
|
|
|
transaction will be closed automatically.
|
|
|
|
</para>
|
1998-12-29 03:24:47 +01:00
|
|
|
</sect2>
|
2000-05-15 14:42:23 +02:00
|
|
|
|
2010-08-09 14:00:24 +02:00
|
|
|
<sect2 id="lo-unlink">
|
2000-05-15 14:42:23 +02:00
|
|
|
<title>Removing a Large Object</title>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
To remove a large object from the database, call
|
|
|
|
<synopsis>
|
2003-03-13 02:30:29 +01:00
|
|
|
int lo_unlink(PGconn *conn, Oid lobjId);
|
2000-05-15 14:42:23 +02:00
|
|
|
</synopsis>
|
2003-08-31 19:32:24 +02:00
|
|
|
<indexterm><primary>lo_unlink</></> The
|
|
|
|
<parameter>lobjId</parameter> argument specifies the OID of the
|
2005-01-08 23:13:38 +01:00
|
|
|
large object to remove. Returns 1 if successful, -1 on failure.
|
2000-05-15 14:42:23 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
</sect1>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2000-09-29 22:21:34 +02:00
|
|
|
<sect1 id="lo-funcs">
|
2011-02-01 23:00:26 +01:00
|
|
|
<title>Server-side Functions</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2005-01-08 23:13:38 +01:00
|
|
|
<para>
|
|
|
|
There are server-side functions callable from SQL that correspond to
|
|
|
|
each of the client-side functions described above; indeed, for the
|
|
|
|
most part the client-side functions are simply interfaces to the
|
|
|
|
equivalent server-side functions. The ones that are actually useful
|
|
|
|
to call via SQL commands are
|
|
|
|
<function>lo_creat</function><indexterm><primary>lo_creat</></>,
|
2005-06-13 04:26:53 +02:00
|
|
|
<function>lo_create</function><indexterm><primary>lo_create</></>,
|
2005-01-08 23:13:38 +01:00
|
|
|
<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</></>.
|
|
|
|
Here are examples of their use:
|
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<programlisting>
|
1998-03-01 09:16:16 +01:00
|
|
|
CREATE TABLE image (
|
|
|
|
name text,
|
|
|
|
raster oid
|
|
|
|
);
|
|
|
|
|
2005-01-08 23:13:38 +01:00
|
|
|
SELECT lo_creat(-1); -- returns OID of new, empty large object
|
|
|
|
|
2005-06-13 04:26:53 +02:00
|
|
|
SELECT lo_create(43213); -- attempts to create large object with OID 43213
|
|
|
|
|
2005-01-08 23:13:38 +01:00
|
|
|
SELECT lo_unlink(173454); -- deletes large object with OID 173454
|
|
|
|
|
1998-03-01 09:16:16 +01:00
|
|
|
INSERT INTO image (name, raster)
|
|
|
|
VALUES ('beautiful image', lo_import('/etc/motd'));
|
|
|
|
|
2008-03-22 02:55:14 +01:00
|
|
|
INSERT INTO image (name, raster) -- same as above, but specify OID to use
|
|
|
|
VALUES ('beautiful image', lo_import('/etc/motd', 68583));
|
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
SELECT lo_export(image.raster, '/tmp/motd') FROM image
|
1998-03-01 09:16:16 +01:00
|
|
|
WHERE name = 'beautiful image';
|
1999-06-14 09:36:12 +02:00
|
|
|
</programlisting>
|
2005-01-08 23:13:38 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
|
|
|
The server-side <function>lo_import</function> and
|
|
|
|
<function>lo_export</function> functions behave considerably differently
|
|
|
|
from their client-side analogs. These two functions read and write files
|
|
|
|
in the server's file system, using the permissions of the database's
|
|
|
|
owning user. Therefore, their use is restricted to superusers. In
|
|
|
|
contrast, the client-side import and export functions read and write files
|
|
|
|
in the client's file system, using the permissions of the client program.
|
2009-12-17 15:36:16 +01:00
|
|
|
The client-side functions do not require superuser privilege.
|
2005-01-08 23:13:38 +01:00
|
|
|
</para>
|
2009-12-11 04:34:57 +01:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
</sect1>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2003-03-13 02:30:29 +01:00
|
|
|
<sect1 id="lo-examplesect">
|
|
|
|
<title>Example Program</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
1999-06-14 09:36:12 +02:00
|
|
|
<para>
|
2010-11-23 21:27:50 +01:00
|
|
|
<xref linkend="lo-example"> is a sample program which shows how the large object
|
1998-03-01 09:16:16 +01:00
|
|
|
interface
|
2010-11-23 21:27:50 +01:00
|
|
|
in <application>libpq</> can be used. Parts of the program are
|
2002-01-07 03:29:15 +01:00
|
|
|
commented out but are left in the source for the reader's
|
2003-03-13 02:30:29 +01:00
|
|
|
benefit. This program can also be found in
|
2002-01-07 03:29:15 +01:00
|
|
|
<filename>src/test/examples/testlo.c</filename> in the source distribution.
|
1999-06-14 09:36:12 +02:00
|
|
|
</para>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<example id="lo-example">
|
2003-03-13 02:30:29 +01:00
|
|
|
<title>Large Objects with <application>libpq</application> Example Program</title>
|
2008-12-08 00:46:39 +01:00
|
|
|
<programlisting><![CDATA[
|
1998-03-01 09:16:16 +01:00
|
|
|
/*--------------------------------------------------------------
|
2000-05-02 22:02:03 +02:00
|
|
|
*
|
|
|
|
* testlo.c--
|
|
|
|
* test using large objects with libpq
|
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*--------------------------------------------------------------
|
|
|
|
*/
|
2008-12-08 00:46:39 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include "libpq-fe.h"
|
|
|
|
#include "libpq/libpq-fs.h"
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
#define BUFSIZE 1024
|
|
|
|
|
|
|
|
/*
|
2001-09-15 18:08:59 +02:00
|
|
|
* importFile
|
2008-12-08 00:46:39 +01:00
|
|
|
* import file "in_filename" into database as large object "lobjOid"
|
2000-05-02 22:02:03 +02:00
|
|
|
*
|
|
|
|
*/
|
2001-01-20 01:05:54 +01:00
|
|
|
Oid
|
|
|
|
importFile(PGconn *conn, char *filename)
|
2000-05-02 22:02:03 +02:00
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
Oid lobjId;
|
|
|
|
int lobj_fd;
|
|
|
|
char buf[BUFSIZE];
|
|
|
|
int nbytes,
|
|
|
|
tmp;
|
|
|
|
int fd;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* open the file to be read in
|
|
|
|
*/
|
|
|
|
fd = open(filename, O_RDONLY, 0666);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (fd < 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{ /* error */
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot open unix file %s\n", filename);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create the large object
|
|
|
|
*/
|
2001-01-20 01:05:54 +01:00
|
|
|
lobjId = lo_creat(conn, INV_READ | INV_WRITE);
|
|
|
|
if (lobjId == 0)
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot create large object\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
|
2001-01-20 01:05:54 +01:00
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
/*
|
|
|
|
* read in from the Unix file and write to the inversion file
|
|
|
|
*/
|
2008-12-08 00:46:39 +01:00
|
|
|
while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
|
|
|
tmp = lo_write(conn, lobj_fd, buf, nbytes);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (tmp < nbytes)
|
|
|
|
fprintf(stderr, "error while reading large object\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
(void) close(fd);
|
|
|
|
(void) lo_close(conn, lobj_fd);
|
|
|
|
|
|
|
|
return lobjId;
|
|
|
|
}
|
|
|
|
|
2001-01-20 01:05:54 +01:00
|
|
|
void
|
|
|
|
pickout(PGconn *conn, Oid lobjId, int start, int len)
|
2000-05-02 22:02:03 +02:00
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
int lobj_fd;
|
|
|
|
char *buf;
|
|
|
|
int nbytes;
|
|
|
|
int nread;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_READ);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (lobj_fd < 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot open large object %d\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
lobjId);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
lo_lseek(conn, lobj_fd, start, SEEK_SET);
|
2001-01-20 01:05:54 +01:00
|
|
|
buf = malloc(len + 1);
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
nread = 0;
|
2008-12-08 00:46:39 +01:00
|
|
|
while (len - nread > 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
|
|
|
nbytes = lo_read(conn, lobj_fd, buf, len - nread);
|
|
|
|
buf[nbytes] = ' ';
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, ">>> %s", buf);
|
2001-01-20 01:05:54 +01:00
|
|
|
nread += nbytes;
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
2001-01-20 01:05:54 +01:00
|
|
|
free(buf);
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
lo_close(conn, lobj_fd);
|
|
|
|
}
|
|
|
|
|
2001-01-20 01:05:54 +01:00
|
|
|
void
|
|
|
|
overwrite(PGconn *conn, Oid lobjId, int start, int len)
|
2000-05-02 22:02:03 +02:00
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
int lobj_fd;
|
|
|
|
char *buf;
|
|
|
|
int nbytes;
|
|
|
|
int nwritten;
|
|
|
|
int i;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2006-03-02 22:49:09 +01:00
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (lobj_fd < 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot open large object %d\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
lobjId);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
lo_lseek(conn, lobj_fd, start, SEEK_SET);
|
2001-01-20 01:05:54 +01:00
|
|
|
buf = malloc(len + 1);
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
for (i = 0; i < len; i++)
|
2001-01-20 01:05:54 +01:00
|
|
|
buf[i] = 'X';
|
2000-05-02 22:02:03 +02:00
|
|
|
buf[i] = ' ';
|
|
|
|
|
|
|
|
nwritten = 0;
|
2008-12-08 00:46:39 +01:00
|
|
|
while (len - nwritten > 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
|
|
|
nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten);
|
|
|
|
nwritten += nbytes;
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
2001-01-20 01:05:54 +01:00
|
|
|
free(buf);
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
lo_close(conn, lobj_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-02 22:49:09 +01:00
|
|
|
* exportFile
|
2008-12-08 00:46:39 +01:00
|
|
|
* export large object "lobjOid" to file "out_filename"
|
2000-05-02 22:02:03 +02:00
|
|
|
*
|
|
|
|
*/
|
2001-01-20 01:05:54 +01:00
|
|
|
void
|
|
|
|
exportFile(PGconn *conn, Oid lobjId, char *filename)
|
2000-05-02 22:02:03 +02:00
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
int lobj_fd;
|
|
|
|
char buf[BUFSIZE];
|
|
|
|
int nbytes,
|
|
|
|
tmp;
|
|
|
|
int fd;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
/*
|
2006-03-02 22:49:09 +01:00
|
|
|
* open the large object
|
2000-05-02 22:02:03 +02:00
|
|
|
*/
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_READ);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (lobj_fd < 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot open large object %d\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
lobjId);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open the file to be written to
|
|
|
|
*/
|
2001-01-20 01:05:54 +01:00
|
|
|
fd = open(filename, O_CREAT | O_WRONLY, 0666);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (fd < 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{ /* error */
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "cannot open unix file %s\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
filename);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-02 22:49:09 +01:00
|
|
|
* read in from the inversion file and write to the Unix file
|
2000-05-02 22:02:03 +02:00
|
|
|
*/
|
2008-12-08 00:46:39 +01:00
|
|
|
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
|
|
|
tmp = write(fd, buf, nbytes);
|
2008-12-08 00:46:39 +01:00
|
|
|
if (tmp < nbytes)
|
2001-01-20 01:05:54 +01:00
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "error while writing %s\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
filename);
|
|
|
|
}
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
(void) lo_close(conn, lobj_fd);
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-01-20 01:05:54 +01:00
|
|
|
exit_nicely(PGconn *conn)
|
2000-05-02 22:02:03 +02:00
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
PQfinish(conn);
|
|
|
|
exit(1);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
2001-01-20 01:05:54 +01:00
|
|
|
char *in_filename,
|
|
|
|
*out_filename;
|
|
|
|
char *database;
|
|
|
|
Oid lobjOid;
|
|
|
|
PGconn *conn;
|
|
|
|
PGresult *res;
|
|
|
|
|
|
|
|
if (argc != 4)
|
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "Usage: %s database_name in_filename out_filename\n",
|
2001-01-20 01:05:54 +01:00
|
|
|
argv[0]);
|
|
|
|
exit(1);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
database = argv[1];
|
|
|
|
in_filename = argv[2];
|
|
|
|
out_filename = argv[3];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set up the connection
|
|
|
|
*/
|
|
|
|
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
|
|
|
|
|
|
|
|
/* check to see that the backend connection was successfully made */
|
2001-01-20 01:05:54 +01:00
|
|
|
if (PQstatus(conn) == CONNECTION_BAD)
|
|
|
|
{
|
2008-12-08 00:46:39 +01:00
|
|
|
fprintf(stderr, "Connection to database '%s' failed.\n", database);
|
|
|
|
fprintf(stderr, "%s", PQerrorMessage(conn));
|
2001-01-20 01:05:54 +01:00
|
|
|
exit_nicely(conn);
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
res = PQexec(conn, "begin");
|
2000-05-02 22:02:03 +02:00
|
|
|
PQclear(res);
|
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
printf("importing file %s\n", in_filename);
|
2000-05-02 22:02:03 +02:00
|
|
|
/* lobjOid = importFile(conn, in_filename); */
|
|
|
|
lobjOid = lo_import(conn, in_filename);
|
|
|
|
/*
|
2008-12-08 00:46:39 +01:00
|
|
|
printf("as large object %d.\n", lobjOid);
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
printf("picking out bytes 1000-2000 of the large object\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
pickout(conn, lobjOid, 1000, 1000);
|
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
printf("overwriting bytes 1000-2000 of the large object with X's\n");
|
2000-05-02 22:02:03 +02:00
|
|
|
overwrite(conn, lobjOid, 1000, 1000);
|
|
|
|
*/
|
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
printf("exporting large object to file %s\n", out_filename);
|
2000-05-02 22:02:03 +02:00
|
|
|
/* exportFile(conn, lobjOid, out_filename); */
|
2001-01-20 01:05:54 +01:00
|
|
|
lo_export(conn, lobjOid, out_filename);
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2008-12-08 00:46:39 +01:00
|
|
|
res = PQexec(conn, "end");
|
2000-05-02 22:02:03 +02:00
|
|
|
PQclear(res);
|
|
|
|
PQfinish(conn);
|
|
|
|
exit(0);
|
|
|
|
}
|
2008-12-08 00:46:39 +01:00
|
|
|
]]>
|
1999-06-14 09:36:12 +02:00
|
|
|
</programlisting>
|
2001-09-15 18:08:59 +02:00
|
|
|
</example>
|
1999-06-14 09:36:12 +02:00
|
|
|
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|