From 5e3bc5ebcddf00ba33d1483bab2a5a2d62c65120 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 2 Dec 2000 20:49:24 +0000 Subject: [PATCH] Avoid memory leakage during regular COPY when outputting toasted values. COPY BINARY is still broken for toasted data, however. --- src/backend/commands/copy.c | 185 +++++++++++++++--------------------- 1 file changed, 75 insertions(+), 110 deletions(-) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index bbbb5aa2cf..6cdba32729 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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 #include -#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 * 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) {