1 /*-------------------------------------------------------------------------
4 * Front-end large object interface
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.20 1999/05/10 00:46:26 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "libpq-int.h"
23 #if !defined(NO_UNISTD_H)
31 #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
34 #define LO_BUFSIZE 1024
36 static int lo_initialize(PGconn *conn);
40 * opens an existing large object
42 * returns the file descriptor for use in later lo_* calls
43 * return -1 upon failure.
46 lo_open(PGconn *conn, Oid lobjId, int mode)
55 argv[0].u.integer = lobjId;
59 argv[1].u.integer = mode;
61 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
63 if (lo_initialize(conn) < 0)
67 res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
68 if (PQresultStatus(res) == PGRES_COMMAND_OK)
72 /* have to do this to reset offset in shared fd cache */
73 /* but only if fd is valid */
74 if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
87 * closes an existing large object
89 * returns 0 upon success
90 * returns -1 upon failure.
93 lo_close(PGconn *conn, int fd)
100 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
102 if (lo_initialize(conn) < 0)
108 argv[0].u.integer = fd;
109 res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
110 &retval, &result_len, 1, argv, 1);
111 if (PQresultStatus(res) == PGRES_COMMAND_OK)
125 * read len bytes of the large object into buf
127 * returns the length of bytes read.
128 * the CALLER must have allocated enough space to hold the result returned
132 lo_read(PGconn *conn, int fd, char *buf, int len)
138 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
140 if (lo_initialize(conn) < 0)
146 argv[0].u.integer = fd;
150 argv[1].u.integer = len;
152 res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
153 (int *) buf, &result_len, 0, argv, 2);
154 if (PQresultStatus(res) == PGRES_COMMAND_OK)
168 * write len bytes of buf into the large object fd
172 lo_write(PGconn *conn, int fd, char *buf, int len)
179 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
181 if (lo_initialize(conn) < 0)
190 argv[0].u.integer = fd;
194 argv[1].u.ptr = (int *) buf;
196 res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
197 &retval, &result_len, 1, argv, 2);
198 if (PQresultStatus(res) == PGRES_COMMAND_OK)
212 * change the current read or write location on a large object
213 * currently, only L_SET is a legal value for whence
218 lo_lseek(PGconn *conn, int fd, int offset, int whence)
225 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
227 if (lo_initialize(conn) < 0)
233 argv[0].u.integer = fd;
237 argv[1].u.integer = offset;
241 argv[2].u.integer = whence;
243 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
244 &retval, &result_len, 1, argv, 3);
245 if (PQresultStatus(res) == PGRES_COMMAND_OK)
259 * create a new large object
260 * the mode is a bitmask describing different attributes of the new object
262 * returns the oid of the large object created or
263 * InvalidOid upon failure
267 lo_creat(PGconn *conn, int mode)
274 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
276 if (lo_initialize(conn) < 0)
282 argv[0].u.integer = mode;
283 res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
284 &retval, &result_len, 1, argv, 1);
285 if (PQresultStatus(res) == PGRES_COMMAND_OK)
300 * returns the current seek location of the large object
305 lo_tell(PGconn *conn, int fd)
312 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
314 if (lo_initialize(conn) < 0)
320 argv[0].u.integer = fd;
322 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
323 &retval, &result_len, 1, argv, 1);
324 if (PQresultStatus(res) == PGRES_COMMAND_OK)
343 lo_unlink(PGconn *conn, Oid lobjId)
350 if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
352 if (lo_initialize(conn) < 0)
358 argv[0].u.integer = lobjId;
360 res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
361 &retval, &result_len, 1, argv, 1);
362 if (PQresultStatus(res) == PGRES_COMMAND_OK)
376 * imports a file as an (inversion) large object.
377 * returns the oid of that object upon success,
378 * returns InvalidOid upon failure
383 lo_import(PGconn *conn, char *filename)
388 char buf[LO_BUFSIZE];
393 * open the file to be read in
396 fd = open(filename, O_RDONLY, 0666);
398 fd = open(filename, O_RDONLY | O_BINARY, 0666);
402 sprintf(conn->errorMessage,
403 "lo_import: can't open unix file\"%s\"\n", filename);
408 * create an inversion "object"
410 lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
411 if (lobjOid == InvalidOid)
413 sprintf(conn->errorMessage,
414 "lo_import: can't create inv object for \"%s\"", filename);
418 lobj = lo_open(conn, lobjOid, INV_WRITE);
421 sprintf(conn->errorMessage,
422 "lo_import: could not open inv object oid %u", lobjOid);
427 * read in from the Unix file and write to the inversion file
429 while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
431 tmp = lo_write(conn, lobj, buf, nbytes);
434 sprintf(conn->errorMessage,
435 "lo_import: error while reading \"%s\"", filename);
441 (void) lo_close(conn, lobj);
448 * exports an (inversion) large object.
449 * returns -1 upon failure, 1 otherwise
452 lo_export(PGconn *conn, Oid lobjId, char *filename)
457 char buf[LO_BUFSIZE];
461 * create an inversion "object"
463 lobj = lo_open(conn, lobjId, INV_READ);
466 sprintf(conn->errorMessage,
467 "lo_export: can't open inv object %u", lobjId);
472 * open the file to be written to
475 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
477 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
481 sprintf(conn->errorMessage,
482 "lo_export: can't open unix file\"%s\"", filename);
487 * read in from the Unix file and write to the inversion file
489 while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
491 tmp = write(fd, buf, nbytes);
494 sprintf(conn->errorMessage,
495 "lo_export: error while writing \"%s\"",
501 (void) lo_close(conn, lobj);
511 * Initialize the large object interface for an existing connection.
512 * We ask the backend about the functions OID's in pg_proc for all
513 * functions that are required for large object operations.
517 lo_initialize(PGconn *conn)
520 PGlobjfuncs *lobjfuncs;
526 * Allocate the structure to hold the functions OID's
529 lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
530 if (lobjfuncs == (PGlobjfuncs *) NULL)
532 strcpy(conn->errorMessage,
533 "FATAL: malloc() failed in lo_initialize()\n");
536 MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
539 * Execute the query to get all the functions at once
542 res = PQexec(conn, "select proname, oid from pg_proc \
543 where proname = 'lo_open' \
544 or proname = 'lo_close' \
545 or proname = 'lo_creat' \
546 or proname = 'lo_unlink' \
547 or proname = 'lo_lseek' \
548 or proname = 'lo_tell' \
549 or proname = 'loread' \
550 or proname = 'lowrite'");
551 if (res == (PGresult *) NULL)
557 if (res->resultStatus != PGRES_TUPLES_OK)
561 strcpy(conn->errorMessage,
562 "ERROR: SELECT didn't return data in lo_initialize()\n");
567 * Examine the result and put the OID's into the struct
570 for (n = 0; n < PQntuples(res); n++)
572 fname = PQgetvalue(res, n, 0);
573 foid = (Oid) atoi(PQgetvalue(res, n, 1));
574 if (!strcmp(fname, "lo_open"))
575 lobjfuncs->fn_lo_open = foid;
576 else if (!strcmp(fname, "lo_close"))
577 lobjfuncs->fn_lo_close = foid;
578 else if (!strcmp(fname, "lo_creat"))
579 lobjfuncs->fn_lo_creat = foid;
580 else if (!strcmp(fname, "lo_unlink"))
581 lobjfuncs->fn_lo_unlink = foid;
582 else if (!strcmp(fname, "lo_lseek"))
583 lobjfuncs->fn_lo_lseek = foid;
584 else if (!strcmp(fname, "lo_tell"))
585 lobjfuncs->fn_lo_tell = foid;
586 else if (!strcmp(fname, "loread"))
587 lobjfuncs->fn_lo_read = foid;
588 else if (!strcmp(fname, "lowrite"))
589 lobjfuncs->fn_lo_write = foid;
595 * Finally check that we really got all large object
596 * interface functions.
599 if (lobjfuncs->fn_lo_open == 0)
601 strcpy(conn->errorMessage,
602 "ERROR: Cannot determine OID for function lo_open\n");
606 if (lobjfuncs->fn_lo_close == 0)
608 strcpy(conn->errorMessage,
609 "ERROR: Cannot determine OID for function lo_close\n");
613 if (lobjfuncs->fn_lo_creat == 0)
615 strcpy(conn->errorMessage,
616 "ERROR: Cannot determine OID for function lo_creat\n");
620 if (lobjfuncs->fn_lo_unlink == 0)
622 strcpy(conn->errorMessage,
623 "ERROR: Cannot determine OID for function lo_unlink\n");
627 if (lobjfuncs->fn_lo_lseek == 0)
629 strcpy(conn->errorMessage,
630 "ERROR: Cannot determine OID for function lo_lseek\n");
634 if (lobjfuncs->fn_lo_tell == 0)
636 strcpy(conn->errorMessage,
637 "ERROR: Cannot determine OID for function lo_tell\n");
641 if (lobjfuncs->fn_lo_read == 0)
643 strcpy(conn->errorMessage,
644 "ERROR: Cannot determine OID for function loread\n");
648 if (lobjfuncs->fn_lo_write == 0)
650 strcpy(conn->errorMessage,
651 "ERROR: Cannot determine OID for function lowrite\n");
657 * Put the structure into the connection control
660 conn->lobjfuncs = lobjfuncs;