head     1.3;
branch   ;
access   ;
symbols  ;
locks    ; strict;
comment  @ * @;


1.3
date     91.09.04.13.48.32;  author kemnitz;  state Exp;
branches ;
next     1.2;

1.2
date     91.08.09.20.36.18;  author kemnitz;  state Exp;
branches ;
next     1.1;

1.1
date     91.08.08.17.35.15;  author kemnitz;  state Exp;
branches ;
next     ;


desc
@Large object interface routines.
@


1.3
log
@fixed problem in computing large object tuple pointer size.
@
text
@/*
 * large_object.c - routines for manipulating and accessing large objects
 *
 * $Header: RCS/large_object.c,v 1.2 91/08/09 20:36:18 kemnitz Exp Locker: kemnitz $
 */

#include <sys/file.h>
#include "tmp/c.h"
#include "utils/large_object.h"

/*
 * These routines allow the user to import and export Postgres PURE_FILE
 * large objects.
 */


long lo_storage_type = PURE_FILE;

char *
lo_filein(filename)

char *filename;

{
    LargeObject *retval;
    long obj_len, filename_len = strlen(filename) + 1;

    obj_len = filename_len
			+ sizeof(LargeObject) - sizeof(LargeObjectDataPtr)
			+ sizeof(long);

    retval = (LargeObject *) palloc(obj_len);

    retval->lo_length = obj_len;

    retval->lo_storage_type = PURE_FILE;

    /*
     * NOTE: if this is a pure file, these numbers cannot be trusted.
     * They should only be used for a postgres file or relation.
     */

    retval->lo_nblocks = retval->lo_lastoff = retval->lo_version = 0;

    strcpy(retval->lo_ptr.filename, filename);

    return((char *) retval);
}

char *
lo_fileout(object)

LargeObject *object;

{
    char *retval; 

    Assert(PointerIsValid(object));

    retval = (char *) palloc(strlen(object->lo_ptr.filename) + 1);

    strcpy(retval, object->lo_ptr.filename);
    return(retval);
}

/*
 * These next routines are the "internal" large object interface for use by
 * user-defined functions.
 */

/*
 * Eventually, LargeObjectCreate should log all filenames in some type of
 * log - this approach will have problems if an object is destroyed.
 */

LargeObjectDesc *
LOCreate(open_mode)

int open_mode;

{
    char filename[256];
    int file_oid;
    LargeObjectDesc *retval;
    LargeObject *newobj;
    int fd;

    file_oid = newoid();
    sprintf(filename, "LO%d", file_oid);

    fd = (int) FileNameOpenFile(filename, O_CREAT | O_RDWR, 0666);
    if (fd == -1) return(NULL);

	newobj = (LargeObject *) lo_filein(filename);

    retval->object = newobj;
    retval->fd = fd;

    return(retval);
}

LargeObjectDesc *
LOOpen(object, open_mode)

LargeObject *object;
int open_mode;

{
    LargeObjectDesc *retval;
    int fd;

    Assert(PointerIsValid(object));
    Assert(object->lo_storage_type == PURE_FILE);

    fd = FileNameOpenFile(object->lo_ptr.filename, open_mode, 0666);

    if (fd == -1) return(NULL);

    retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));

    retval->fd = fd;
    retval->object = object;
    return(retval);
}

/*
 * Returns the number of blocks and the byte offset of the last block of
 * the file.  nblocks * LARGE_OBJECT_BLOCK + byte_offset should be equal to
 * the file size.
 */

void
LOStat(obj_desc, nblocks, byte_offset)

LargeObjectDesc *obj_desc;
unsigned int *nblocks, *byte_offset;

{
    unsigned long nbytes;
    unsigned long pos, len;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    /* see where we are now */

    pos = FileTell(obj_desc->fd);

    /* do a seek to find number of bytes */

    len = FileSeek(obj_desc->fd, 0L, L_XTND);

    /* seek back to original position */

    FileSeek(obj_desc->fd, pos, L_SET);

    *nblocks = (len < 0) ? 0 : len / LARGE_OBJECT_BLOCK;
    *byte_offset = len % LARGE_OBJECT_BLOCK;
}

/*
 * Returns the number of bytes read in the last block - zero on failed read.
 */

int
LOBlockRead(obj_desc, buf, nblocks)

LargeObjectDesc *obj_desc;
char *buf;
unsigned long nblocks;

{
    unsigned long nbytes, bytes_read;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    nbytes = LARGE_OBJECT_BLOCK * nblocks;
    bytes_read = FileRead(obj_desc->fd, buf, nbytes);

    if (bytes_read == 0) return(0);

    if (bytes_read % LARGE_OBJECT_BLOCK != 0)
        return(bytes_read % LARGE_OBJECT_BLOCK);
    else
        return(LARGE_OBJECT_BLOCK);
}

/*
 * here, bytes_at_end allows an incomplete block to be written.
 * This should ONLY be used to end a file, since we only allow block-oriented
 * seeking.  IF bytes_in
 */

int
LOBlockWrite(obj_desc, buf, n_whole_blocks, bytes_at_end)

LargeObjectDesc *obj_desc;
char *buf;
unsigned long n_whole_blocks, bytes_at_end;

{
    unsigned long totalbytes;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    totalbytes = LARGE_OBJECT_BLOCK * n_whole_blocks + bytes_at_end;

    return(FileWrite(obj_desc->fd, buf, totalbytes));
}

/*
 * Just like seek, although "offset" is the block offset, and the return
 * value is a block number.
 */

unsigned long
LOBlockSeek(obj_desc, offset, whence)

LargeObjectDesc *obj_desc;
unsigned long offset;
int whence;

{
    unsigned long retval;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    retval = FileSeek(obj_desc->fd, offset * LARGE_OBJECT_BLOCK, whence);

    return(retval * LARGE_OBJECT_BLOCK);
}

/*
 * Closes an existing large object descriptor.
 */

void
LOClose(obj_desc)

LargeObjectDesc *obj_desc;

{
    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    FileClose(obj_desc->fd);
    pfree(obj_desc);
}

/*
 * Destroys an existing large object, and frees its associated pointers.
 * Currently deletes the large object file.
 */

void
LODestroy(object)

LargeObject *object;

{
    Assert(PointerIsValid(object));
    Assert(object->lo_storage_type == PURE_FILE);

    FileNameUnlink(object->lo_ptr.filename);
    pfree(object);
}

/*
 * To be called at the end of the use of a large object, just before the
 * large object is closed.
 */

LargeObject *
LODescToObject(obj_desc)

LargeObjectDesc *obj_desc;

{
    LargeObject *retval;

    Assert(PointerIsValid(obj_desc));
    Assert(PointerIsValid(obj_desc->object));
    Assert(obj_desc->object->lo_storage_type == PURE_FILE);

    retval = obj_desc->object;
    return(retval);
}
@


1.2
log
@various fixes.
@
text
@d4 1
a4 1
 * $Header: RCS/large_object.c,v 1.1 91/08/08 17:35:15 kemnitz Exp Locker: kemnitz $
d26 1
a26 1
    int obj_len, filename_len = strlen(filename) + 1;
d28 3
a30 1
    obj_len = filename_len + sizeof(LargeObject) - sizeof(LargeObjectDataPtr);
d36 1
a36 1
    retval->lo_storage_type = lo_storage_type;
d94 1
a94 6
    retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
    retval->fd = fd;
    newobj = (LargeObject *) palloc(sizeof(LargeObject));
    newobj->lo_length = sizeof(LargeObject)
                      - sizeof(LargeObjectDataPtr)
                      + strlen(filename) + 1; 
a95 7
    /*
     * Eventually, the Executor will set a global object type that 
     */

    newobj->lo_storage_type = PURE_FILE;
    newobj->lo_nblocks = newobj->lo_lastoff = newobj->lo_version = 0;
    strcpy(newobj->lo_ptr.filename, filename);
d97 1
@


1.1
log
@Initial revision
@
text
@d4 1
a4 1
 * $Header: RCS/large_object.h,v 1.1 90/11/12 12:06:38 kemnitz Exp $
d19 2
a20 2
LargeObject *
LOFileIn(filename)
d36 4
a39 4
	/*
	 * NOTE: if this is a pure file, these numbers cannot be trusted.
	 * They should only be used for a postgres file or relation.
	 */
d45 1
a45 1
    return(retval);
d49 1
a49 1
LOFileOut(object)
d56 1
a56 1
	Assert(PointerIsValid(object));
d58 1
a58 1
	retval = (char *) palloc(strlen(object->lo_ptr.filename) + 1);
d89 1
a89 1
    fd = (int) FileNameOpenFile(filename, O_CREAT | O_RDWR);
d118 2
a119 2
	LargeObjectDesc *retval;
	int fd;
d121 2
a122 2
	Assert(PointerIsValid(object));
	Assert(object->lo_storage_type == PURE_FILE);
d124 1
a124 1
	fd = FileNameOpenFile(object->lo_ptr.filename, open_mode);
d126 1
a126 1
	if (fd == -1) return(NULL);
d128 1
a128 1
	retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
d130 3
a132 3
	retval->fd = fd;
	retval->object = object;
	return(retval);
d137 2
a138 1
 * the file.
d148 2
a149 2
	unsigned long nbytes;
	unsigned long pos, len;
d151 3
a153 3
	Assert(PointerIsValid(obj_desc));
	Assert(PointerIsValid(obj_desc->object));
	Assert(obj_desc->object->lo_storage_type == PURE_FILE);
d155 1
a155 1
	/* see where we are now */
d157 1
a157 1
	pos = FileTell(obj_desc->fd);
d159 1
a159 1
	/* do a seek to find number of bytes */
d161 1
a161 1
	len = FileSeek(obj_desc->fd, 0L, L_XTND) - 1;
d163 1
a163 1
	/* seek back to original position */
d165 1
a165 1
	FileSeek(obj_desc->fd, pos, L_SET);
d167 2
a168 3
	*nblocks = (len < 0) ? 0 : 1 + len / LARGE_OBJECT_BLOCK;
	*byte_offset = len % LARGE_OBJECT_BLOCK; 
	if (*byte_offset == 0 && *nblocks != 0) (*nblocks)--;
d183 1
a183 1
	unsigned long nbytes, bytes_read;
d185 3
a187 3
	Assert(PointerIsValid(obj_desc));
	Assert(PointerIsValid(obj_desc->object));
	Assert(obj_desc->object->lo_storage_type == PURE_FILE);
d189 2
a190 2
	nbytes = LARGE_OBJECT_BLOCK * nblocks;
	bytes_read = FileRead(obj_desc->fd, buf, nbytes);
d192 1
a192 1
	if (bytes_read == 0) return(0);
d194 4
a197 4
	if (bytes_read % LARGE_OBJECT_BLOCK != 0)
		return(bytes_read % LARGE_OBJECT_BLOCK);
	else
		return(LARGE_OBJECT_BLOCK);
d214 1
a214 1
	unsigned long totalbytes;
d216 3
a218 3
	Assert(PointerIsValid(obj_desc));
	Assert(PointerIsValid(obj_desc->object));
	Assert(obj_desc->object->lo_storage_type == PURE_FILE);
d220 1
a220 1
	totalbytes = LARGE_OBJECT_BLOCK * n_whole_blocks + bytes_at_end;
d222 1
a222 1
	return(FileWrite(obj_desc->fd, buf, totalbytes));
d226 24
d260 2
a261 2
	Assert(PointerIsValid(obj_desc->object));
	Assert(obj_desc->object->lo_storage_type == PURE_FILE);
d263 2
a264 2
	FileClose(obj_desc->fd);
	obj_desc->fd = -1;
d278 2
a279 2
	Assert(PointerIsValid(object));
	Assert(object->lo_storage_type == PURE_FILE);
d281 2
a282 2
	FileUnlink(object->lo_ptr.filename);
	pfree(object);
d286 2
a287 3
 * To be called at the end of the use of a large object.
 * Frees the large object descriptor associated with an object and returns
 * the object itself.
d296 1
a296 1
	LargeObject *retval;
d299 2
a300 2
	Assert(PointerIsValid(obj_desc->object));
	Assert(obj_desc->object->lo_storage_type == PURE_FILE);
d302 2
a303 3
	retval = obj_desc->object;
	pfree(obj_desc);
	return(retval);
@
