]> granicus.if.org Git - postgresql/commitdiff
Avoid memory leakage during regular COPY when outputting toasted values.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Dec 2000 20:49:24 +0000 (20:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Dec 2000 20:49:24 +0000 (20:49 +0000)
COPY BINARY is still broken for toasted data, however.

src/backend/commands/copy.c

index bbbb5aa2cfcb446109bdf1df498876452c85a18f..6cdba327295b5a251f762ef70c61bbd8e1951ded 100644 (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"
 /* 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)
 {