Avoid memory leakage during regular COPY when outputting toasted values.

COPY BINARY is still broken for toasted data, however.
This commit is contained in:
Tom Lane 2000-12-02 20:49:24 +00:00
parent 77698e11a9
commit 5e3bc5ebcd
1 changed files with 75 additions and 110 deletions

View File

@ -7,18 +7,18 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.124 2000/11/16 22:30:19 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.125 2000/12/02 20:49:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <unistd.h>
#include <sys/stat.h>
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/printtup.h"
#include "catalog/catname.h"
#include "catalog/index.h"
#include "catalog/pg_index.h"
@ -47,13 +47,11 @@
/* non-export function prototypes */
static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
static Oid GetOutputFunction(Oid type);
static Oid GetInputFunction(Oid type);
static Oid GetTypeElement(Oid type);
static bool IsTypeByVal(Oid type);
static void CopyReadNewline(FILE *fp, int *newline);
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
static void CopyAttributeOut(FILE *fp, char *string, char *delim);
static int CountTuples(Relation relation);
@ -61,7 +59,7 @@ static int CountTuples(Relation relation);
* Static communication variables ... pretty grotty, but COPY has
* never been reentrant...
*/
int lineno = 0; /* used by elog() -- dz */
int lineno = 0; /* exported for use by elog() -- dz */
static bool fe_eof;
/*
@ -344,7 +342,11 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
{
mode_t oumask; /* Pre-existing umask value */
if (*filename != '/')
/*
* Prevent write to relative path ... too easy to shoot oneself
* in the foot by overwriting a database file ...
*/
if (filename[0] != '/')
elog(ERROR, "Relative path not allowed for server side"
" COPY command.");
@ -382,27 +384,22 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
}
/*
* Copy from relation TO file.
*/
static void
CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
HeapScanDesc scandesc;
int32 attr_count,
int attr_count,
i;
#ifdef _DROP_COLUMN_HACK__
bool *valid;
#endif /* _DROP_COLUMN_HACK__ */
Form_pg_attribute *attr;
FmgrInfo *out_functions;
Oid out_func_oid;
Oid *elements;
bool *isvarlena;
int32 *typmod;
Datum value;
bool isnull; /* The attribute we are copying is null */
char *nulls;
/*
@ -413,47 +410,39 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
* <nulls> is meaningful only if we are doing a binary copy.
*/
char *string;
int32 ntuples;
TupleDesc tupDesc;
scandesc = heap_beginscan(rel, 0, QuerySnapshot, 0, NULL);
tupDesc = rel->rd_att;
attr_count = rel->rd_att->natts;
attr = rel->rd_att->attrs;
tupDesc = rel->rd_att;
/* For binary copy we really only need isvarlena, but compute it all... */
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
elements = (Oid *) palloc(attr_count * sizeof(Oid));
isvarlena = (bool *) palloc(attr_count * sizeof(bool));
typmod = (int32 *) palloc(attr_count * sizeof(int32));
for (i = 0; i < attr_count; i++)
{
Oid out_func_oid;
if (!getTypeOutputInfo(attr[i]->atttypid,
&out_func_oid, &elements[i], &isvarlena[i]))
elog(ERROR, "COPY: couldn't lookup info for type %u",
attr[i]->atttypid);
fmgr_info(out_func_oid, &out_functions[i]);
typmod[i] = attr[i]->atttypmod;
}
if (!binary)
{
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
elements = (Oid *) palloc(attr_count * sizeof(Oid));
typmod = (int32 *) palloc(attr_count * sizeof(int32));
#ifdef _DROP_COLUMN_HACK__
valid = (bool *) palloc(attr_count * sizeof(bool));
#endif /* _DROP_COLUMN_HACK__ */
for (i = 0; i < attr_count; i++)
{
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(attr[i]))
{
valid[i] = false;
continue;
}
else
valid[i] = true;
#endif /* _DROP_COLUMN_HACK__ */
out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
fmgr_info(out_func_oid, &out_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid);
typmod[i] = attr[i]->atttypmod;
}
nulls = NULL; /* meaningless, but compiler doesn't know
* that */
}
else
{
elements = NULL;
typmod = NULL;
out_functions = NULL;
int32 ntuples;
nulls = (char *) palloc(attr_count);
for (i = 0; i < attr_count; i++)
nulls[i] = ' ';
@ -480,18 +469,31 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
for (i = 0; i < attr_count; i++)
{
value = heap_getattr(tuple, i + 1, tupDesc, &isnull);
if (!binary)
Datum origvalue,
value;
bool isnull;
origvalue = heap_getattr(tuple, i + 1, tupDesc, &isnull);
if (isnull)
{
#ifdef _DROP_COLUMN_HACK__
if (!valid[i])
{
if (i == attr_count - 1)
CopySendChar('\n', fp);
continue;
}
#endif /* _DROP_COLUMN_HACK__ */
if (!isnull)
if (!binary)
CopySendString(null_print, fp); /* null indicator */
else
nulls[i] = 'n';
}
else
{
/*
* If we have a toasted datum, forcibly detoast it to avoid
* memory leakage inside the type's output routine.
*/
if (isvarlena[i])
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
else
value = origvalue;
if (!binary)
{
string = DatumGetCString(FunctionCall3(&out_functions[i],
value,
@ -500,9 +502,14 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
CopyAttributeOut(fp, string, delim);
pfree(string);
}
else
CopySendString(null_print, fp); /* null indicator */
/* Clean up detoasted copy, if any */
if (value != origvalue)
pfree(DatumGetPointer(value));
}
if (!binary)
{
if (i == attr_count - 1)
CopySendChar('\n', fp);
else
@ -515,16 +522,6 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
CopySendChar(delim[0], fp);
}
}
else
{
/*
* only interesting thing heap_getattr tells us in this
* case is if we have a null attribute or not.
*/
if (isnull)
nulls[i] = 'n';
}
}
if (binary)
@ -561,16 +558,19 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
}
heap_endscan(scandesc);
pfree(out_functions);
pfree(elements);
pfree(isvarlena);
pfree(typmod);
if (binary)
pfree(nulls);
else
{
pfree(out_functions);
pfree(elements);
pfree(typmod);
}
}
/*
* Copy FROM file to relation.
*/
static void
CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
char *delim, char *null_print)
@ -635,10 +635,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
typmod = (int32 *) palloc(attr_count * sizeof(int32));
for (i = 0; i < attr_count; i++)
{
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(attr[i]))
continue;
#endif /* _DROP_COLUMN_HACK__ */
in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
fmgr_info(in_func_oid, &in_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid);
@ -662,13 +658,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
for (i = 0; i < attr_count; i++)
{
nulls[i] = ' ';
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(attr[i]))
{
byval[i] = 'n';
continue;
}
#endif /* _DROP_COLUMN_HACK__ */
byval[i] = IsTypeByVal(attr[i]->atttypid);
}
@ -704,14 +693,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
}
for (i = 0; i < attr_count && !done; i++)
{
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(attr[i]))
{
values[i] = PointerGetDatum(NULL);
nulls[i] = 'n';
continue;
}
#endif /* _DROP_COLUMN_HACK__ */
string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print);
if (isnull)
{
@ -889,22 +870,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
}
static Oid
GetOutputFunction(Oid type)
{
HeapTuple typeTuple;
Oid result;
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(type),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "GetOutputFunction: Cache lookup of type %u failed", type);
result = ((Form_pg_type) GETSTRUCT(typeTuple))->typoutput;
ReleaseSysCache(typeTuple);
return result;
}
static Oid
GetInputFunction(Oid type)
{