1 /*-------------------------------------------------------------------------
4 * Front-end large object interface
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.30 2000/06/02 15:57:42 momjian Exp $
13 *-------------------------------------------------------------------------
21 #include "libpq-int.h"
30 #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
33 #define LO_BUFSIZE 1024
35 static int lo_initialize(PGconn *conn);
39 * opens an existing large object
41 * returns the file descriptor for use in later lo_* calls
42 * return -1 upon failure.
45 lo_open(PGconn *conn, Oid lobjId, int mode)
54 argv[0].u.integer = lobjId;
58 argv[1].u.integer = mode;
60 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
62 if (lo_initialize(conn) < 0)
66 res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
67 if (PQresultStatus(res) == PGRES_COMMAND_OK)
71 /* have to do this to reset offset in shared fd cache */
72 /* but only if fd is valid */
73 if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
86 * closes an existing large object
88 * returns 0 upon success
89 * returns -1 upon failure.
92 lo_close(PGconn *conn, int fd)
99 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
101 if (lo_initialize(conn) < 0)
107 argv[0].u.integer = fd;
108 res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
109 &retval, &result_len, 1, argv, 1);
110 if (PQresultStatus(res) == PGRES_COMMAND_OK)
124 * read len bytes of the large object into buf
126 * returns the length of bytes read.
127 * the CALLER must have allocated enough space to hold the result returned
131 lo_read(PGconn *conn, int fd, char *buf, size_t len)
137 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
139 if (lo_initialize(conn) < 0)
145 argv[0].u.integer = fd;
149 argv[1].u.integer = len;
151 res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
152 (int *) buf, &result_len, 0, argv, 2);
153 if (PQresultStatus(res) == PGRES_COMMAND_OK)
167 * write len bytes of buf into the large object fd
171 lo_write(PGconn *conn, int fd, char *buf, size_t len)
178 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
180 if (lo_initialize(conn) < 0)
189 argv[0].u.integer = fd;
193 argv[1].u.ptr = (int *) buf;
195 res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
196 &retval, &result_len, 1, argv, 2);
197 if (PQresultStatus(res) == PGRES_COMMAND_OK)
211 * change the current read or write location on a large object
212 * currently, only L_SET is a legal value for whence
217 lo_lseek(PGconn *conn, int fd, int offset, int whence)
224 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
226 if (lo_initialize(conn) < 0)
232 argv[0].u.integer = fd;
236 argv[1].u.integer = offset;
240 argv[2].u.integer = whence;
242 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
243 &retval, &result_len, 1, argv, 3);
244 if (PQresultStatus(res) == PGRES_COMMAND_OK)
258 * create a new large object
259 * the mode is a bitmask describing different attributes of the new object
261 * returns the oid of the large object created or
262 * InvalidOid upon failure
266 lo_creat(PGconn *conn, int mode)
273 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
275 if (lo_initialize(conn) < 0)
281 argv[0].u.integer = mode;
282 res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
283 &retval, &result_len, 1, argv, 1);
284 if (PQresultStatus(res) == PGRES_COMMAND_OK)
299 * returns the current seek location of the large object
304 lo_tell(PGconn *conn, int fd)
311 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
313 if (lo_initialize(conn) < 0)
319 argv[0].u.integer = fd;
321 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
322 &retval, &result_len, 1, argv, 1);
323 if (PQresultStatus(res) == PGRES_COMMAND_OK)
342 lo_unlink(PGconn *conn, Oid lobjId)
349 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
351 if (lo_initialize(conn) < 0)
357 argv[0].u.integer = lobjId;
359 res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
360 &retval, &result_len, 1, argv, 1);
361 if (PQresultStatus(res) == PGRES_COMMAND_OK)
375 * imports a file as an (inversion) large object.
376 * returns the oid of that object upon success,
377 * returns InvalidOid upon failure
382 lo_import(PGconn *conn, const char *filename)
387 char buf[LO_BUFSIZE];
392 * open the file to be read in
394 fd = open(filename, O_RDONLY | PG_BINARY, 0666);
397 printfPQExpBuffer(&conn->errorMessage,
398 "lo_import: can't open unix file\"%s\"\n",
404 * create an inversion "object"
406 lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
407 if (lobjOid == InvalidOid)
409 printfPQExpBuffer(&conn->errorMessage,
410 "lo_import: can't create inv object for \"%s\"",
415 lobj = lo_open(conn, lobjOid, INV_WRITE);
418 printfPQExpBuffer(&conn->errorMessage,
419 "lo_import: could not open inv object oid %u",
425 * read in from the Unix file and write to the inversion file
427 while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
429 tmp = lo_write(conn, lobj, buf, nbytes);
432 printfPQExpBuffer(&conn->errorMessage,
433 "lo_import: error while reading \"%s\"",
440 (void) lo_close(conn, lobj);
447 * exports an (inversion) large object.
448 * returns -1 upon failure, 1 otherwise
451 lo_export(PGconn *conn, Oid lobjId, const char *filename)
456 char buf[LO_BUFSIZE];
460 * create an inversion "object"
462 lobj = lo_open(conn, lobjId, INV_READ);
465 printfPQExpBuffer(&conn->errorMessage,
466 "lo_export: can't open inv object %u", lobjId);
471 * open the file to be written to
473 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
476 printfPQExpBuffer(&conn->errorMessage,
477 "lo_export: can't open unix file\"%s\"",
483 * read in from the Unix file and write to the inversion file
485 while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
487 tmp = write(fd, buf, nbytes);
490 printfPQExpBuffer(&conn->errorMessage,
491 "lo_export: error while writing \"%s\"",
497 (void) lo_close(conn, lobj);
507 * Initialize the large object interface for an existing connection.
508 * We ask the backend about the functions OID's in pg_proc for all
509 * functions that are required for large object operations.
513 lo_initialize(PGconn *conn)
516 PGlobjfuncs *lobjfuncs;
522 * Allocate the structure to hold the functions OID's
525 lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
526 if (lobjfuncs == (PGlobjfuncs *) NULL)
528 printfPQExpBuffer(&conn->errorMessage,
529 "FATAL: malloc() failed in lo_initialize()\n");
532 MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
535 * Execute the query to get all the functions at once
538 res = PQexec(conn, "select proname, oid from pg_proc \
539 where proname = 'lo_open' \
540 or proname = 'lo_close' \
541 or proname = 'lo_creat' \
542 or proname = 'lo_unlink' \
543 or proname = 'lo_lseek' \
544 or proname = 'lo_tell' \
545 or proname = 'loread' \
546 or proname = 'lowrite'");
547 if (res == (PGresult *) NULL)
553 if (res->resultStatus != PGRES_TUPLES_OK)
557 printfPQExpBuffer(&conn->errorMessage,
558 "ERROR: SELECT didn't return data in lo_initialize()\n");
563 * Examine the result and put the OID's into the struct
566 for (n = 0; n < PQntuples(res); n++)
568 fname = PQgetvalue(res, n, 0);
569 foid = (Oid) atoi(PQgetvalue(res, n, 1));
570 if (!strcmp(fname, "lo_open"))
571 lobjfuncs->fn_lo_open = foid;
572 else if (!strcmp(fname, "lo_close"))
573 lobjfuncs->fn_lo_close = foid;
574 else if (!strcmp(fname, "lo_creat"))
575 lobjfuncs->fn_lo_creat = foid;
576 else if (!strcmp(fname, "lo_unlink"))
577 lobjfuncs->fn_lo_unlink = foid;
578 else if (!strcmp(fname, "lo_lseek"))
579 lobjfuncs->fn_lo_lseek = foid;
580 else if (!strcmp(fname, "lo_tell"))
581 lobjfuncs->fn_lo_tell = foid;
582 else if (!strcmp(fname, "loread"))
583 lobjfuncs->fn_lo_read = foid;
584 else if (!strcmp(fname, "lowrite"))
585 lobjfuncs->fn_lo_write = foid;
591 * Finally check that we really got all large object
592 * interface functions.
595 if (lobjfuncs->fn_lo_open == 0)
597 printfPQExpBuffer(&conn->errorMessage,
598 "ERROR: Cannot determine OID for function lo_open\n");
602 if (lobjfuncs->fn_lo_close == 0)
604 printfPQExpBuffer(&conn->errorMessage,
605 "ERROR: Cannot determine OID for function lo_close\n");
609 if (lobjfuncs->fn_lo_creat == 0)
611 printfPQExpBuffer(&conn->errorMessage,
612 "ERROR: Cannot determine OID for function lo_creat\n");
616 if (lobjfuncs->fn_lo_unlink == 0)
618 printfPQExpBuffer(&conn->errorMessage,
619 "ERROR: Cannot determine OID for function lo_unlink\n");
623 if (lobjfuncs->fn_lo_lseek == 0)
625 printfPQExpBuffer(&conn->errorMessage,
626 "ERROR: Cannot determine OID for function lo_lseek\n");
630 if (lobjfuncs->fn_lo_tell == 0)
632 printfPQExpBuffer(&conn->errorMessage,
633 "ERROR: Cannot determine OID for function lo_tell\n");
637 if (lobjfuncs->fn_lo_read == 0)
639 printfPQExpBuffer(&conn->errorMessage,
640 "ERROR: Cannot determine OID for function loread\n");
644 if (lobjfuncs->fn_lo_write == 0)
646 printfPQExpBuffer(&conn->errorMessage,
647 "ERROR: Cannot determine OID for function lowrite\n");
653 * Put the structure into the connection control
656 conn->lobjfuncs = lobjfuncs;