mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <HTML>
 | |
| <HEAD>
 | |
| 	<TITLE>The POSTGRES95 User Manual - LARGE OBJECTS</TITLE>
 | |
| </HEAD>
 | |
| 
 | |
| <BODY>
 | |
| 
 | |
| <font size=-1>
 | |
| <A HREF="pg95user.html">[ TOC ]</A> 
 | |
| <A HREF="libpq.html">[ Previous ]</A> 
 | |
| <A HREF="rules.html">[ Next ]</A> 
 | |
| </font>
 | |
| <HR>
 | |
| <H1>13.  LARGE OBJECTS</H1>
 | |
| <HR>
 | |
|      In POSTGRES, data values are stored in tuples and 
 | |
|      individual tuples cannot span data pages. Since the size of
 | |
|      a data page is 8192 bytes, the upper limit on the  size
 | |
|      of a data value is relatively low. To support the storage 
 | |
|      of larger atomic values, POSTGRES provides a  large
 | |
|      object   interface.    This  interface  provides  file
 | |
|      oriented access to user data that has been declared  to
 | |
|      be a large type.
 | |
|      This  section describes the implementation and the 
 | |
|      programmatic and query  language  interfaces  to  POSTGRES
 | |
|      large object data.
 | |
| 
 | |
| <H2><A NAME="historical-note">13.1.  Historical Note</A></H2>
 | |
|      Originally, <B>POSTGRES 4.2</B> supports three standard 
 | |
|      implementations of large objects: as files external 
 | |
|      to POSTGRES,  as  <B>UNIX</B>  files managed by POSTGRES, and as data
 | |
|      stored within the POSTGRES database. It causes  
 | |
|      considerable confusion among users. As a result, we only 
 | |
|      support large objects as data stored within  the  POSTGRES
 | |
|      database  in  <B>POSTGRES95</B>.  Even  though is is slower to
 | |
|      access, it provides stricter data  integrity  and  time
 | |
|      travel.  For historical reasons, they are called 
 | |
|      Inversion large objects. (We will use  Inversion  and  large
 | |
|      objects  interchangeably to mean the same thing in this
 | |
|      section.)
 | |
| 
 | |
| <H2><A NAME="inversion-large-objects">13.2.  Inversion Large Objects</A></H2>
 | |
|      The Inversion large object implementation breaks  large
 | |
|      objects  up  into  "chunks"  and  stores  the chunks in
 | |
|      tuples in the database.  A B-tree index guarantees fast
 | |
|      searches for the correct chunk number when doing random
 | |
|      access reads and writes.
 | |
| 
 | |
| <H2><A NAME="large-object-interfaces">13.3.  Large Object Interfaces</A></H2>
 | |
|      The  facilities  POSTGRES  provides  to  access   large
 | |
|      objects,  both  in  the backend as part of user-defined
 | |
|      functions or the front end as part  of  an  application
 | |
|      using  the   interface, are described below. (For users
 | |
|      familiar with <B>POSTGRES 4.2</B>, <B>POSTGRES95</B> has a new set of
 | |
|      functions  providing  a  more  coherent  interface. The
 | |
|      interface is the same for  dynamically-loaded  C  
 | |
|      functions as well as for .
 | |
|      The  POSTGRES  large  object interface is modeled after
 | |
|      the <B>UNIX</B>  file  system  interface,  with  analogues  of
 | |
|      <B>open(2),  read(2), write(2), lseek(2)</B>, etc.  User 
 | |
|      functions call these routines to retrieve only the data  of
 | |
|      interest  from a large object.  For example, if a large
 | |
|      object type called mugshot  existed  that  stored  
 | |
|      photographs  of  faces, then a function called beard could
 | |
|      be declared on mugshot data.  Beard could look  at  the
 | |
|      lower third of a photograph, and determine the color of
 | |
|      the beard that appeared  there,  if  any.   The  entire
 | |
|      large  object value need not be buffered, or even 
 | |
|      examined, by the beard function.
 | |
|      Large objects may be accessed from dynamically-loaded <B>C</B>
 | |
|      functions  or  database  client  programs that link the
 | |
|      library.  POSTGRES provides a set of routines that 
 | |
|      support opening, reading, writing, closing, and seeking on
 | |
|      large objects.
 | |
| <p>
 | |
| <H3><A NAME="creating-large-objects">13.3.1.  Creating a Large Object</A></H3>
 | |
|      The routine
 | |
| <pre>         Oid lo_creat(PGconn *conn, int mode)
 | |
| </pre>
 | |
|      creates a new large  object.  The  mode  is  a  bitmask
 | |
|      describing  several  different  attributes  of  the new
 | |
|      object.  The symbolic constants listed here are defined
 | |
|      in
 | |
| <pre>         /usr/local/postgres95/src/backend/libpq/libpq-fs.h
 | |
| </pre>
 | |
|      The access type (read, write, or both) is controlled by
 | |
|      OR ing together the bits <B>INV_READ</B>  and  <B>INV_WRITE</B>.   If
 | |
|      the large object should be archived -- that is, if 
 | |
|      historical versions of it should be moved periodically  to
 | |
|      a  special archive relation -- then the <B>INV_ARCHIVE</B> bit
 | |
|      should be set.  The low-order sixteen bits of mask  are
 | |
|      the  storage  manager  number on which the large object
 | |
|      should reside.  For sites other  than  Berkeley,  these
 | |
|      bits should always be zero.
 | |
|      The commands below create an (Inversion) large object:
 | |
| <pre>         inv_oid = lo_creat(INV_READ|INV_WRITE|INV_ARCHIVE);
 | |
| </pre>
 | |
| 
 | |
| <H3><A NAME="importing-a-large-object">13.3.2.  Importing a Large Object</A></H3>
 | |
| To import a <B>UNIX</B> file as
 | |
|      a large object, call
 | |
| <pre>         Oid
 | |
|          lo_import(PGconn *conn, text *filename)
 | |
| </pre>
 | |
|      The filename argument specifies the  <B>UNIX</B>  pathname  of
 | |
|      the file to be imported as a large object.
 | |
| <p>
 | |
| <H3><A NAME="exporting-a-large-object">13.3.3.  Exporting a Large Object</A></H3>
 | |
| To export a large object
 | |
|      into <B>UNIX</B> file, call
 | |
| <pre>         int
 | |
|          lo_export(PGconn *conn, Oid lobjId, text *filename)
 | |
| </pre>
 | |
|      The lobjId argument specifies  the  Oid  of  the  large
 | |
|      object  to  export  and the filename argument specifies
 | |
|      the <B>UNIX</B> pathname of the file.
 | |
| <p>
 | |
| <H3><A NAME="opening-an-existing-large-object">13.3.4.  Opening an Existing Large Object</A></H3>
 | |
|      To open an existing large object, call
 | |
| <pre>         int
 | |
|          lo_open(PGconn *conn, Oid lobjId, int mode, ...)
 | |
| </pre>
 | |
|      The lobjId argument specifies  the  Oid  of  the  large
 | |
|      object  to  open.   The  mode  bits control whether the
 | |
|      object is opened  for  reading  INV_READ),  writing  or
 | |
|      both.
 | |
|      A  large  object cannot be opened before it is created.
 | |
|      lo_open returns a large object descriptor for later use
 | |
|      in  lo_read, lo_write, lo_lseek, lo_tell, and lo_close.
 | |
| <p>
 | |
| <H3><A NAME="writing-data-to-a-large-object">13.3.5.  Writing Data to a Large Object</A></H3>
 | |
|      The routine
 | |
| <pre>         int
 | |
|          lo_write(PGconn *conn, int fd, char *buf, int len)
 | |
| </pre>
 | |
|      writes len bytes from buf to large object fd.   The  fd
 | |
|      argument must have been returned by a previous lo_open.
 | |
|      The number of bytes actually written is  returned.   In
 | |
|      the event of an error, the return value is negative.
 | |
| <p>
 | |
| <H3><A NAME="seeking-on-a-large-object">13.3.6.  Seeking on a Large Object</A></H3>
 | |
|      To change the current read or write location on a large
 | |
|      object, call
 | |
| <pre>         int
 | |
|          lo_lseek(PGconn *conn, int fd, int offset, int whence)
 | |
| </pre>
 | |
|      This routine moves the current location pointer for the
 | |
|      large object described by fd to the new location specified 
 | |
|      by offset.  The valid values  for  .i  whence  are
 | |
|      SEEK_SET SEEK_CUR and SEEK_END.
 | |
| <p>
 | |
| <H3><A NAME="closing-a-large-object-descriptor">13.3.7.  Closing a Large Object Descriptor</A></H3>
 | |
|      A large object may be closed by calling
 | |
| <pre>         int
 | |
|          lo_close(PGconn *conn, int fd)
 | |
| </pre>
 | |
|      where  fd  is  a  large  object  descriptor returned by
 | |
|      lo_open.  On success, <B>lo_close</B> returns zero.  On error,
 | |
|      the return value is negative.
 | |
| 
 | |
| <H2><A NAME="built-in-registered-functions">13.4.  Built in registered functions</A></H2>
 | |
|      There  are two built-in registered functions, <B>lo_import</B>
 | |
|      and <B>lo_export</B> which  are  convenient  for  use  in  <B>SQL</B>
 | |
|      queries.
 | |
|      Here is an example of there use
 | |
| <pre>         CREATE TABLE image (
 | |
|                  name            text,
 | |
|                  raster          oid
 | |
|          );
 | |
| 
 | |
|          INSERT INTO image (name, raster)
 | |
|             VALUES ('beautiful image', lo_import('/etc/motd'));
 | |
| 
 | |
|          SELECT lo_export(image.raster, "/tmp/motd") from image
 | |
|             WHERE name = 'beautiful image';
 | |
| </pre>
 | |
| <H2><A NAME="accessing-large-objects-from-libpq">13.5.   Accessing Large Objects from LIBPQ</A></H2>
 | |
|      Below is a sample program which shows how the large object  
 | |
|      interface
 | |
|      in  LIBPQ  can  be used.  Parts of the program are 
 | |
|      commented out but are left in the source for  the  readers
 | |
|      benefit.  This program can be found in
 | |
| <pre>         ../src/test/examples
 | |
| </pre>
 | |
|      Frontend applications which use the large object interface  
 | |
|      in  LIBPQ  should   include   the   header   file
 | |
|      libpq/libpq-fs.h and link with the libpq library.
 | |
| 
 | |
| <H2><A NAME="sample-program">13.6.  Sample Program</A></H2>
 | |
| <pre>         /*--------------------------------------------------------------
 | |
|           *
 | |
|           * testlo.c--
 | |
|           *    test using large objects with libpq
 | |
|           *
 | |
|           * Copyright (c) 1994, Regents of the University of California
 | |
|           *
 | |
|           *
 | |
|           * IDENTIFICATION
 | |
|           *    /usr/local/devel/pglite/cvs/src/doc/manual.me,v 1.16 1995/09/01 23:55:00 jolly Exp
 | |
|           *
 | |
|           *--------------------------------------------------------------
 | |
|           */
 | |
|          #include <stdio.h>
 | |
|          #include "libpq-fe.h"
 | |
|          #include "libpq/libpq-fs.h"
 | |
| <p>
 | |
|          #define BUFSIZE          1024
 | |
| <p>
 | |
|          /*
 | |
|           * importFile *    import file "in_filename" into database as large object "lobjOid"
 | |
|           *
 | |
|           */
 | |
|          Oid importFile(PGconn *conn, char *filename)
 | |
|          {
 | |
|              Oid lobjId;
 | |
|              int lobj_fd;
 | |
|              char buf[BUFSIZE];
 | |
|              int nbytes, tmp;
 | |
|              int fd;
 | |
| <p>
 | |
|              /*
 | |
|               * open the file to be read in
 | |
|               */
 | |
|              fd = open(filename, O_RDONLY, 0666);
 | |
|              if (fd < 0)  {   /* error */
 | |
|               fprintf(stderr, "can't open unix file
 | |
|              }
 | |
| <p>
 | |
|              /*
 | |
|               * create the large object
 | |
|               */
 | |
|              lobjId = lo_creat(conn, INV_READ|INV_WRITE);
 | |
|              if (lobjId == 0) {
 | |
|               fprintf(stderr, "can't create large object");
 | |
|              }
 | |
| <p>
 | |
|              lobj_fd = lo_open(conn, lobjId, INV_WRITE);
 | |
|              /*
 | |
|               * read in from the Unix file and write to the inversion file
 | |
|               */
 | |
|              while ((nbytes = read(fd, buf, BUFSIZE)) > 0) {
 | |
|               tmp = lo_write(conn, lobj_fd, buf, nbytes);
 | |
|               if (tmp < nbytes) {
 | |
|                   fprintf(stderr, "error while reading
 | |
|               }
 | |
|              }
 | |
| <p>
 | |
|              (void) close(fd);
 | |
|              (void) lo_close(conn, lobj_fd);
 | |
| <p>
 | |
|              return lobjId;
 | |
|          }
 | |
| <p>
 | |
|          void pickout(PGconn *conn, Oid lobjId, int start, int len)
 | |
|          {
 | |
|              int lobj_fd;
 | |
|              char* buf;
 | |
|              int nbytes;
 | |
|              int nread;
 | |
| <p>
 | |
|              lobj_fd = lo_open(conn, lobjId, INV_READ);
 | |
|              if (lobj_fd < 0) {
 | |
|               fprintf(stderr,"can't open large object %d",
 | |
|                    lobjId);
 | |
|              }
 | |
| <p>
 | |
|              lo_lseek(conn, lobj_fd, start, SEEK_SET);
 | |
|              buf = malloc(len+1);
 | |
| <p>
 | |
|              nread = 0;
 | |
|              while (len - nread > 0) {
 | |
|               nbytes = lo_read(conn, lobj_fd, buf, len - nread);
 | |
|               buf[nbytes] = ' ';
 | |
|               fprintf(stderr,">>> %s", buf);
 | |
|               nread += nbytes;
 | |
|              }
 | |
|              fprintf(stderr,"0);
 | |
|              lo_close(conn, lobj_fd);
 | |
|          }
 | |
| <p>
 | |
|          void overwrite(PGconn *conn, Oid lobjId, int start, int len)
 | |
|          {
 | |
|              int lobj_fd;
 | |
|              char* buf;
 | |
|              int nbytes;
 | |
|              int nwritten;
 | |
|              int i;
 | |
| <p>
 | |
|              lobj_fd = lo_open(conn, lobjId, INV_READ);
 | |
|              if (lobj_fd < 0) {
 | |
|               fprintf(stderr,"can't open large object %d",
 | |
|                    lobjId);
 | |
|              }
 | |
| <p>
 | |
|              lo_lseek(conn, lobj_fd, start, SEEK_SET);
 | |
|              buf = malloc(len+1);
 | |
| <p>
 | |
|              for (i=0;i<len;i++)
 | |
|               buf[i] = 'X';
 | |
|              buf[i] = ' ';
 | |
| <p>
 | |
|              nwritten = 0;
 | |
|              while (len - nwritten > 0) {
 | |
|               nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten);
 | |
|               nwritten += nbytes;
 | |
|              }
 | |
|              fprintf(stderr,"0);
 | |
|              lo_close(conn, lobj_fd);
 | |
|          }
 | |
| <p>
 | |
| 
 | |
|          /*
 | |
|           * exportFile *    export large object "lobjOid" to file "out_filename"
 | |
|           *
 | |
|           */
 | |
|          void exportFile(PGconn *conn, Oid lobjId, char *filename)
 | |
|          {
 | |
|              int lobj_fd;
 | |
|              char buf[BUFSIZE];
 | |
|              int nbytes, tmp;
 | |
|              int fd;
 | |
| <p>
 | |
|              /*
 | |
|               * create an inversion "object"
 | |
|               */
 | |
|              lobj_fd = lo_open(conn, lobjId, INV_READ);
 | |
|              if (lobj_fd < 0) {
 | |
|               fprintf(stderr,"can't open large object %d",
 | |
|                    lobjId);
 | |
|              }
 | |
| <p>
 | |
|              /*
 | |
|               * open the file to be written to
 | |
|               */
 | |
|              fd = open(filename, O_CREAT|O_WRONLY, 0666);
 | |
|              if (fd < 0)  {   /* error */
 | |
|               fprintf(stderr, "can't open unix file
 | |
|                    filename);
 | |
|              }
 | |
| <p>
 | |
|              /*
 | |
|               * read in from the Unix file and write to the inversion file
 | |
|               */
 | |
|              while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) {
 | |
|               tmp = write(fd, buf, nbytes);
 | |
|                  if (tmp < nbytes) {
 | |
|                   fprintf(stderr,"error while writing
 | |
|                        filename);
 | |
|               }
 | |
|              }
 | |
| <p>
 | |
|              (void) lo_close(conn, lobj_fd);
 | |
|              (void) close(fd);
 | |
| <p>
 | |
|              return;
 | |
|          }
 | |
| <p>
 | |
|          void
 | |
|          exit_nicely(PGconn* conn)
 | |
|          {
 | |
|            PQfinish(conn);
 | |
|            exit(1);
 | |
|          }
 | |
| <p>
 | |
|          int
 | |
|          main(int argc, char **argv)
 | |
|          {
 | |
|              char *in_filename, *out_filename;
 | |
|              char *database;
 | |
|              Oid lobjOid;
 | |
|              PGconn *conn;
 | |
|              PGresult *res;
 | |
| <p>
 | |
|              if (argc != 4) {
 | |
|               fprintf(stderr, "Usage: %s database_name in_filename out_filename0,
 | |
|                    argv[0]);
 | |
|               exit(1);
 | |
|              }
 | |
| <p>
 | |
|              database = argv[1];
 | |
|              in_filename = argv[2];
 | |
|              out_filename = argv[3];
 | |
| <p>
 | |
|              /*
 | |
|               * set up the connection
 | |
|               */
 | |
|              conn = PQsetdb(NULL, NULL, NULL, NULL, database);
 | |
| <p>
 | |
|              /* check to see that the backend connection was successfully made */
 | |
|              if (PQstatus(conn) == CONNECTION_BAD) {
 | |
|               fprintf(stderr,"Connection to database '%s' failed.0, database);
 | |
|               fprintf(stderr,"%s",PQerrorMessage(conn));
 | |
|               exit_nicely(conn);
 | |
|              }
 | |
| <p>
 | |
|              res = PQexec(conn, "begin");
 | |
|              PQclear(res);
 | |
| 
 | |
|              printf("importing file
 | |
|          /*  lobjOid = importFile(conn, in_filename); */
 | |
|              lobjOid = lo_import(conn, in_filename);
 | |
|          /*
 | |
|              printf("as large object %d.0, lobjOid);
 | |
| <p>
 | |
|              printf("picking out bytes 1000-2000 of the large object0);
 | |
|              pickout(conn, lobjOid, 1000, 1000);
 | |
| <p>
 | |
|              printf("overwriting bytes 1000-2000 of the large object with X's0);
 | |
|              overwrite(conn, lobjOid, 1000, 1000);
 | |
|          */
 | |
| <p>
 | |
|              printf("exporting large object to file
 | |
|          /*    exportFile(conn, lobjOid, out_filename); */
 | |
|              lo_export(conn, lobjOid,out_filename);
 | |
| <p>
 | |
|              res = PQexec(conn, "end");
 | |
|              PQclear(res);
 | |
|              PQfinish(conn);
 | |
|              exit(0);
 | |
|          }
 | |
| </pre>
 | |
| <HR>
 | |
| <font size=-1>
 | |
| <A HREF="pg95user.html">[ TOC ]</A> 
 | |
| <A HREF="libpq.html">[ Previous ]</A> 
 | |
| <A HREF="rules.html">[ Next ]</A> 
 | |
| </font>
 | |
| </BODY>
 | |
| </HTML>
 |