/*

   $Id: large_object.c,v 1.6 2005/01/03 15:23:49 turnstep Exp $

   Copyright (c) 2003-2005 PostgreSQL Global Development Group
   
   You may distribute under the terms of either the GNU General Public
   License or the Artistic License, as specified in the Perl README file.

*/

int
pg_db_lo_open (dbh, lobjId, mode)
		 SV *dbh;
		 unsigned int lobjId;
		 int mode;
{
	D_imp_dbh(dbh);
	return lo_open(imp_dbh->conn, lobjId, mode);
}


int
pg_db_lo_close (dbh, fd)
		SV *dbh;
		int fd;
{
		D_imp_dbh(dbh);
		return lo_close(imp_dbh->conn, fd);
}


int
pg_db_lo_read (dbh, fd, buf, len)
		SV *dbh;
		int fd;
		char *buf;
		int len;
{
		D_imp_dbh(dbh);
		return lo_read(imp_dbh->conn, fd, buf, len);
}


int
pg_db_lo_write (dbh, fd, buf, len)
		SV *dbh;
		int fd;
		char *buf;
		int len;
{
		D_imp_dbh(dbh);
		return lo_write(imp_dbh->conn, fd, buf, len);
}


int
pg_db_lo_lseek (dbh, fd, offset, whence)
		SV *dbh;
		int fd;
		int offset;
		int whence;
{
		D_imp_dbh(dbh);
		return lo_lseek(imp_dbh->conn, fd, offset, whence);
}


unsigned int
pg_db_lo_creat (dbh, mode)
		SV *dbh;
		int mode;
{
		D_imp_dbh(dbh);
		return lo_creat(imp_dbh->conn, mode);
}


int
pg_db_lo_tell (dbh, fd)
		SV *dbh;
		int fd;
{
		D_imp_dbh(dbh);
		return lo_tell(imp_dbh->conn, fd);
}


int
pg_db_lo_unlink (dbh, lobjId)
		SV *dbh;
		unsigned int lobjId;
{
		D_imp_dbh(dbh);
		return lo_unlink(imp_dbh->conn, lobjId);
}


unsigned int
pg_db_lo_import (dbh, filename)
		SV *dbh;
		char *filename;
{
		D_imp_dbh(dbh);
		return lo_import(imp_dbh->conn, filename);
}


int
pg_db_lo_export (dbh, lobjId, filename)
		SV *dbh;
		unsigned int lobjId;
		char *filename;
{
		D_imp_dbh(dbh);
		return lo_export(imp_dbh->conn, lobjId, filename);
}


int
dbd_st_blob_read (sth, imp_sth, lobjId, offset, len, destrv, destoffset)
		SV *sth;
		imp_sth_t *imp_sth;
		int lobjId;
		long offset;
		long len;
		SV *destrv;
		long destoffset;
{
		D_imp_dbh_from_sth;
		int ret, lobj_fd, nbytes, nread;
		/* PGresult* result;
		ExecStatusType status; */
		SV *bufsv;
		char *tmp;

		if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_blob_read\n"); }
		/* safety check */
		if (lobjId <= 0) {
				pg_error(sth, -1, "dbd_st_blob_read: lobjId <= 0");
				return 0;
		}
		if (offset < 0) {
				pg_error(sth, -1, "dbd_st_blob_read: offset < 0");
				return 0;
		}
		if (len < 0) {
				pg_error(sth, -1, "dbd_st_blob_read: len < 0");
				return 0;
		}
		if (! SvROK(destrv)) {
				pg_error(sth, -1, "dbd_st_blob_read: destrv not a reference");
				return 0;
		}
		if (destoffset < 0) {
				pg_error(sth, -1, "dbd_st_blob_read: destoffset < 0");
				return 0;
		}

		/* dereference destination and ensure it's writable string */
		bufsv = SvRV(destrv);
		if (! destoffset) {
				sv_setpvn(bufsv, "", 0);
		}

		/* execute begin
		result = PQexec(imp_dbh->conn, "begin");
		status = result ? PQresultStatus(result) : -1;
		PQclear(result);
		if (status != PGRES_COMMAND_OK) {
				pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
				return 0;
		}
		*/

		/* open large object */
		lobj_fd = lo_open(imp_dbh->conn, lobjId, INV_READ);
		if (lobj_fd < 0) {
				pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
				return 0;
		}

		/* seek on large object */
		if (offset > 0) {
				ret = lo_lseek(imp_dbh->conn, lobj_fd, offset, SEEK_SET);
				if (ret < 0) {
						pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
						return 0;
				}
		}

		/* read from large object */
		nread = 0;
		SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
		tmp = (SvPVX(bufsv)) + destoffset + nread;
		while ((nbytes = lo_read(imp_dbh->conn, lobj_fd, tmp, BUFSIZ)) > 0) {
				nread += nbytes;
				/* break if user wants only a specified chunk */
				if (len > 0 && nread > len) {
						nread = len;
						break;
				}
				SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
				tmp = (SvPVX(bufsv)) + destoffset + nread;
		}

		/* terminate string */
		SvCUR_set(bufsv, destoffset + nread);
		*SvEND(bufsv) = '\0';

		/* close large object */
		ret = lo_close(imp_dbh->conn, lobj_fd);
		if (ret < 0) {
				pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
				return 0;
		}

		/* execute end 
		result = PQexec(imp_dbh->conn, "end");
		status = result ? PQresultStatus(result) : -1;
		PQclear(result);
		if (status != PGRES_COMMAND_OK) {
				pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
				return 0;
		}
		*/

		return nread;
}


/* end of large_object.c */

