fe-lobj.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
- /*-------------------------------------------------------------------------
- *
- * fe-lobj.c
- * Front-end large object interface
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.20 1999/05/10 00:46:26 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
- #include "libpq-fe.h"
- #include "libpq-int.h"
- #include "postgres.h"
- #ifdef WIN32
- #include "win32.h"
- #include <io.h>
- #else
- #if !defined(NO_UNISTD_H)
- #include <unistd.h>
- #endif
- #endif
- #include <string.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
- #define LO_BUFSIZE 1024
- static int lo_initialize(PGconn *conn);
- /*
- * lo_open
- * opens an existing large object
- *
- * returns the file descriptor for use in later lo_* calls
- * return -1 upon failure.
- */
- int
- lo_open(PGconn *conn, Oid lobjId, int mode)
- {
- int fd;
- int result_len;
- PQArgBlock argv[2];
- PGresult *res;
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = lobjId;
- argv[1].isint = 1;
- argv[1].len = 4;
- argv[1].u.integer = mode;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- /* have to do this to reset offset in shared fd cache */
- /* but only if fd is valid */
- if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
- return -1;
- return fd;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_close
- * closes an existing large object
- *
- * returns 0 upon success
- * returns -1 upon failure.
- */
- int
- lo_close(PGconn *conn, int fd)
- {
- PQArgBlock argv[1];
- PGresult *res;
- int retval;
- int result_len;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
- &retval, &result_len, 1, argv, 1);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return retval;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_read
- * read len bytes of the large object into buf
- *
- * returns the length of bytes read.
- * the CALLER must have allocated enough space to hold the result returned
- */
- int
- lo_read(PGconn *conn, int fd, char *buf, int len)
- {
- PQArgBlock argv[2];
- PGresult *res;
- int result_len;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = fd;
- argv[1].isint = 1;
- argv[1].len = 4;
- argv[1].u.integer = len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
- (int *) buf, &result_len, 0, argv, 2);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return result_len;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_write
- * write len bytes of buf into the large object fd
- *
- */
- int
- lo_write(PGconn *conn, int fd, char *buf, int len)
- {
- PQArgBlock argv[2];
- PGresult *res;
- int result_len;
- int retval;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- if (len <= 0)
- return 0;
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = fd;
- argv[1].isint = 0;
- argv[1].len = len;
- argv[1].u.ptr = (int *) buf;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
- &retval, &result_len, 1, argv, 2);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return retval;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_lseek
- * change the current read or write location on a large object
- * currently, only L_SET is a legal value for whence
- *
- */
- int
- lo_lseek(PGconn *conn, int fd, int offset, int whence)
- {
- PQArgBlock argv[3];
- PGresult *res;
- int retval;
- int result_len;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = fd;
- argv[1].isint = 1;
- argv[1].len = 4;
- argv[1].u.integer = offset;
- argv[2].isint = 1;
- argv[2].len = 4;
- argv[2].u.integer = whence;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
- &retval, &result_len, 1, argv, 3);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return retval;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_creat
- * create a new large object
- * the mode is a bitmask describing different attributes of the new object
- *
- * returns the oid of the large object created or
- * InvalidOid upon failure
- */
- Oid
- lo_creat(PGconn *conn, int mode)
- {
- PQArgBlock argv[1];
- PGresult *res;
- int retval;
- int result_len;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = mode;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
- &retval, &result_len, 1, argv, 1);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return (Oid) retval;
- }
- else
- {
- PQclear(res);
- return InvalidOid;
- }
- }
- /*
- * lo_tell
- * returns the current seek location of the large object
- *
- */
- int
- lo_tell(PGconn *conn, int fd)
- {
- int retval;
- PQArgBlock argv[1];
- PGresult *res;
- int result_len;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
- &retval, &result_len, 1, argv, 1);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return retval;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_unlink
- * delete a file
- *
- */
- int
- lo_unlink(PGconn *conn, Oid lobjId)
- {
- PQArgBlock argv[1];
- PGresult *res;
- int result_len;
- int retval;
- if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
- {
- if (lo_initialize(conn) < 0)
- return -1;
- }
- argv[0].isint = 1;
- argv[0].len = 4;
- argv[0].u.integer = lobjId;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
- &retval, &result_len, 1, argv, 1);
- if (PQresultStatus(res) == PGRES_COMMAND_OK)
- {
- PQclear(res);
- return retval;
- }
- else
- {
- PQclear(res);
- return -1;
- }
- }
- /*
- * lo_import -
- * imports a file as an (inversion) large object.
- * returns the oid of that object upon success,
- * returns InvalidOid upon failure
- *
- */
- Oid
- lo_import(PGconn *conn, char *filename)
- {
- int fd;
- int nbytes,
- tmp;
- char buf[LO_BUFSIZE];
- Oid lobjOid;
- int lobj;
- /*
- * open the file to be read in
- */
- #ifndef __CYGWIN32__
- fd = open(filename, O_RDONLY, 0666);
- #else
- fd = open(filename, O_RDONLY | O_BINARY, 0666);
- #endif
- if (fd < 0)
- { /* error */
- sprintf(conn->errorMessage,
- "lo_import: can't open unix file"%s"n", filename);
- return InvalidOid;
- }
- /*
- * create an inversion "object"
- */
- lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
- if (lobjOid == InvalidOid)
- {
- sprintf(conn->errorMessage,
- "lo_import: can't create inv object for "%s"", filename);
- return InvalidOid;
- }
- lobj = lo_open(conn, lobjOid, INV_WRITE);
- if (lobj == -1)
- {
- sprintf(conn->errorMessage,
- "lo_import: could not open inv object oid %u", lobjOid);
- return InvalidOid;
- }
- /*
- * read in from the Unix file and write to the inversion file
- */
- while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
- {
- tmp = lo_write(conn, lobj, buf, nbytes);
- if (tmp < nbytes)
- {
- sprintf(conn->errorMessage,
- "lo_import: error while reading "%s"", filename);
- return InvalidOid;
- }
- }
- (void) close(fd);
- (void) lo_close(conn, lobj);
- return lobjOid;
- }
- /*
- * lo_export -
- * exports an (inversion) large object.
- * returns -1 upon failure, 1 otherwise
- */
- int
- lo_export(PGconn *conn, Oid lobjId, char *filename)
- {
- int fd;
- int nbytes,
- tmp;
- char buf[LO_BUFSIZE];
- int lobj;
- /*
- * create an inversion "object"
- */
- lobj = lo_open(conn, lobjId, INV_READ);
- if (lobj == -1)
- {
- sprintf(conn->errorMessage,
- "lo_export: can't open inv object %u", lobjId);
- return -1;
- }
- /*
- * open the file to be written to
- */
- #ifndef __CYGWIN32__
- fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
- #else
- fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
- #endif
- if (fd < 0)
- { /* error */
- sprintf(conn->errorMessage,
- "lo_export: can't open unix file"%s"", filename);
- return 0;
- }
- /*
- * read in from the Unix file and write to the inversion file
- */
- while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
- {
- tmp = write(fd, buf, nbytes);
- if (tmp < nbytes)
- {
- sprintf(conn->errorMessage,
- "lo_export: error while writing "%s"",
- filename);
- return -1;
- }
- }
- (void) lo_close(conn, lobj);
- (void) close(fd);
- return 1;
- }
- /* ----------------
- * lo_initialize
- *
- * Initialize the large object interface for an existing connection.
- * We ask the backend about the functions OID's in pg_proc for all
- * functions that are required for large object operations.
- * ----------------
- */
- static int
- lo_initialize(PGconn *conn)
- {
- PGresult *res;
- PGlobjfuncs *lobjfuncs;
- int n;
- char *fname;
- Oid foid;
- /* ----------------
- * Allocate the structure to hold the functions OID's
- * ----------------
- */
- lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
- if (lobjfuncs == (PGlobjfuncs *) NULL)
- {
- strcpy(conn->errorMessage,
- "FATAL: malloc() failed in lo_initialize()n");
- return -1;
- }
- MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
- /* ----------------
- * Execute the query to get all the functions at once
- * ----------------
- */
- res = PQexec(conn, "select proname, oid from pg_proc
- where proname = 'lo_open'
- or proname = 'lo_close'
- or proname = 'lo_creat'
- or proname = 'lo_unlink'
- or proname = 'lo_lseek'
- or proname = 'lo_tell'
- or proname = 'loread'
- or proname = 'lowrite'");
- if (res == (PGresult *) NULL)
- {
- free(lobjfuncs);
- return -1;
- }
- if (res->resultStatus != PGRES_TUPLES_OK)
- {
- free(lobjfuncs);
- PQclear(res);
- strcpy(conn->errorMessage,
- "ERROR: SELECT didn't return data in lo_initialize()n");
- return -1;
- }
- /* ----------------
- * Examine the result and put the OID's into the struct
- * ----------------
- */
- for (n = 0; n < PQntuples(res); n++)
- {
- fname = PQgetvalue(res, n, 0);
- foid = (Oid) atoi(PQgetvalue(res, n, 1));
- if (!strcmp(fname, "lo_open"))
- lobjfuncs->fn_lo_open = foid;
- else if (!strcmp(fname, "lo_close"))
- lobjfuncs->fn_lo_close = foid;
- else if (!strcmp(fname, "lo_creat"))
- lobjfuncs->fn_lo_creat = foid;
- else if (!strcmp(fname, "lo_unlink"))
- lobjfuncs->fn_lo_unlink = foid;
- else if (!strcmp(fname, "lo_lseek"))
- lobjfuncs->fn_lo_lseek = foid;
- else if (!strcmp(fname, "lo_tell"))
- lobjfuncs->fn_lo_tell = foid;
- else if (!strcmp(fname, "loread"))
- lobjfuncs->fn_lo_read = foid;
- else if (!strcmp(fname, "lowrite"))
- lobjfuncs->fn_lo_write = foid;
- }
- PQclear(res);
- /* ----------------
- * Finally check that we really got all large object
- * interface functions.
- * ----------------
- */
- if (lobjfuncs->fn_lo_open == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_openn");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_close == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_closen");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_creat == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_creatn");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_unlink == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_unlinkn");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_lseek == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_lseekn");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_tell == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lo_telln");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_read == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function loreadn");
- free(lobjfuncs);
- return -1;
- }
- if (lobjfuncs->fn_lo_write == 0)
- {
- strcpy(conn->errorMessage,
- "ERROR: Cannot determine OID for function lowriten");
- free(lobjfuncs);
- return -1;
- }
- /* ----------------
- * Put the structure into the connection control
- * ----------------
- */
- conn->lobjfuncs = lobjfuncs;
- return 0;
- }