Skip to content

Commit 5e3bc5e

Browse files
committed
Avoid memory leakage during regular COPY when outputting toasted values.
COPY BINARY is still broken for toasted data, however.
1 parent 77698e1 commit 5e3bc5e

File tree

1 file changed

+75
-110
lines changed

1 file changed

+75
-110
lines changed

src/backend/commands/copy.c

Lines changed: 75 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.124 2000/11/16 22:30:19 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.125 2000/12/02 20:49:24 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
14+
#include "postgres.h"
1415

1516
#include <unistd.h>
1617
#include <sys/stat.h>
1718

18-
#include "postgres.h"
19-
2019
#include "access/genam.h"
2120
#include "access/heapam.h"
21+
#include "access/printtup.h"
2222
#include "catalog/catname.h"
2323
#include "catalog/index.h"
2424
#include "catalog/pg_index.h"
@@ -47,21 +47,19 @@
4747
/* non-export function prototypes */
4848
static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
4949
static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
50-
static Oid GetOutputFunction(Oid type);
5150
static Oid GetInputFunction(Oid type);
5251
static Oid GetTypeElement(Oid type);
5352
static bool IsTypeByVal(Oid type);
5453
static void CopyReadNewline(FILE *fp, int *newline);
5554
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
56-
5755
static void CopyAttributeOut(FILE *fp, char *string, char *delim);
5856
static int CountTuples(Relation relation);
5957

6058
/*
6159
* Static communication variables ... pretty grotty, but COPY has
6260
* never been reentrant...
6361
*/
64-
int lineno = 0; /* used by elog() -- dz */
62+
int lineno = 0; /* exported for use by elog() -- dz */
6563
static bool fe_eof;
6664

6765
/*
@@ -344,7 +342,11 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
344342
{
345343
mode_t oumask; /* Pre-existing umask value */
346344

347-
if (*filename != '/')
345+
/*
346+
* Prevent write to relative path ... too easy to shoot oneself
347+
* in the foot by overwriting a database file ...
348+
*/
349+
if (filename[0] != '/')
348350
elog(ERROR, "Relative path not allowed for server side"
349351
" COPY command.");
350352

@@ -382,27 +384,22 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
382384
}
383385

384386

385-
387+
/*
388+
* Copy from relation TO file.
389+
*/
386390
static void
387391
CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print)
388392
{
389393
HeapTuple tuple;
394+
TupleDesc tupDesc;
390395
HeapScanDesc scandesc;
391-
392-
int32 attr_count,
396+
int attr_count,
393397
i;
394-
395-
#ifdef _DROP_COLUMN_HACK__
396-
bool *valid;
397-
398-
#endif /* _DROP_COLUMN_HACK__ */
399398
Form_pg_attribute *attr;
400399
FmgrInfo *out_functions;
401-
Oid out_func_oid;
402400
Oid *elements;
401+
bool *isvarlena;
403402
int32 *typmod;
404-
Datum value;
405-
bool isnull; /* The attribute we are copying is null */
406403
char *nulls;
407404

408405
/*
@@ -413,47 +410,39 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
413410
* <nulls> is meaningful only if we are doing a binary copy.
414411
*/
415412
char *string;
416-
int32 ntuples;
417-
TupleDesc tupDesc;
418413

419414
scandesc = heap_beginscan(rel, 0, QuerySnapshot, 0, NULL);
420415

416+
tupDesc = rel->rd_att;
421417
attr_count = rel->rd_att->natts;
422418
attr = rel->rd_att->attrs;
423-
tupDesc = rel->rd_att;
419+
420+
/* For binary copy we really only need isvarlena, but compute it all... */
421+
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
422+
elements = (Oid *) palloc(attr_count * sizeof(Oid));
423+
isvarlena = (bool *) palloc(attr_count * sizeof(bool));
424+
typmod = (int32 *) palloc(attr_count * sizeof(int32));
425+
for (i = 0; i < attr_count; i++)
426+
{
427+
Oid out_func_oid;
428+
429+
if (!getTypeOutputInfo(attr[i]->atttypid,
430+
&out_func_oid, &elements[i], &isvarlena[i]))
431+
elog(ERROR, "COPY: couldn't lookup info for type %u",
432+
attr[i]->atttypid);
433+
fmgr_info(out_func_oid, &out_functions[i]);
434+
typmod[i] = attr[i]->atttypmod;
435+
}
424436

425437
if (!binary)
426438
{
427-
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
428-
elements = (Oid *) palloc(attr_count * sizeof(Oid));
429-
typmod = (int32 *) palloc(attr_count * sizeof(int32));
430-
#ifdef _DROP_COLUMN_HACK__
431-
valid = (bool *) palloc(attr_count * sizeof(bool));
432-
#endif /* _DROP_COLUMN_HACK__ */
433-
for (i = 0; i < attr_count; i++)
434-
{
435-
#ifdef _DROP_COLUMN_HACK__
436-
if (COLUMN_IS_DROPPED(attr[i]))
437-
{
438-
valid[i] = false;
439-
continue;
440-
}
441-
else
442-
valid[i] = true;
443-
#endif /* _DROP_COLUMN_HACK__ */
444-
out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
445-
fmgr_info(out_func_oid, &out_functions[i]);
446-
elements[i] = GetTypeElement(attr[i]->atttypid);
447-
typmod[i] = attr[i]->atttypmod;
448-
}
449439
nulls = NULL; /* meaningless, but compiler doesn't know
450440
* that */
451441
}
452442
else
453443
{
454-
elements = NULL;
455-
typmod = NULL;
456-
out_functions = NULL;
444+
int32 ntuples;
445+
457446
nulls = (char *) palloc(attr_count);
458447
for (i = 0; i < attr_count; i++)
459448
nulls[i] = ' ';
@@ -480,18 +469,31 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
480469

481470
for (i = 0; i < attr_count; i++)
482471
{
483-
value = heap_getattr(tuple, i + 1, tupDesc, &isnull);
484-
if (!binary)
472+
Datum origvalue,
473+
value;
474+
bool isnull;
475+
476+
origvalue = heap_getattr(tuple, i + 1, tupDesc, &isnull);
477+
478+
if (isnull)
485479
{
486-
#ifdef _DROP_COLUMN_HACK__
487-
if (!valid[i])
488-
{
489-
if (i == attr_count - 1)
490-
CopySendChar('\n', fp);
491-
continue;
492-
}
493-
#endif /* _DROP_COLUMN_HACK__ */
494-
if (!isnull)
480+
if (!binary)
481+
CopySendString(null_print, fp); /* null indicator */
482+
else
483+
nulls[i] = 'n';
484+
}
485+
else
486+
{
487+
/*
488+
* If we have a toasted datum, forcibly detoast it to avoid
489+
* memory leakage inside the type's output routine.
490+
*/
491+
if (isvarlena[i])
492+
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
493+
else
494+
value = origvalue;
495+
496+
if (!binary)
495497
{
496498
string = DatumGetCString(FunctionCall3(&out_functions[i],
497499
value,
@@ -500,9 +502,14 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
500502
CopyAttributeOut(fp, string, delim);
501503
pfree(string);
502504
}
503-
else
504-
CopySendString(null_print, fp); /* null indicator */
505505

506+
/* Clean up detoasted copy, if any */
507+
if (value != origvalue)
508+
pfree(DatumGetPointer(value));
509+
}
510+
511+
if (!binary)
512+
{
506513
if (i == attr_count - 1)
507514
CopySendChar('\n', fp);
508515
else
@@ -515,16 +522,6 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
515522
CopySendChar(delim[0], fp);
516523
}
517524
}
518-
else
519-
{
520-
521-
/*
522-
* only interesting thing heap_getattr tells us in this
523-
* case is if we have a null attribute or not.
524-
*/
525-
if (isnull)
526-
nulls[i] = 'n';
527-
}
528525
}
529526

530527
if (binary)
@@ -561,16 +558,19 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
561558
}
562559

563560
heap_endscan(scandesc);
561+
562+
pfree(out_functions);
563+
pfree(elements);
564+
pfree(isvarlena);
565+
pfree(typmod);
564566
if (binary)
565567
pfree(nulls);
566-
else
567-
{
568-
pfree(out_functions);
569-
pfree(elements);
570-
pfree(typmod);
571-
}
572568
}
573569

570+
571+
/*
572+
* Copy FROM file to relation.
573+
*/
574574
static void
575575
CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
576576
char *delim, char *null_print)
@@ -635,10 +635,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
635635
typmod = (int32 *) palloc(attr_count * sizeof(int32));
636636
for (i = 0; i < attr_count; i++)
637637
{
638-
#ifdef _DROP_COLUMN_HACK__
639-
if (COLUMN_IS_DROPPED(attr[i]))
640-
continue;
641-
#endif /* _DROP_COLUMN_HACK__ */
642638
in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
643639
fmgr_info(in_func_oid, &in_functions[i]);
644640
elements[i] = GetTypeElement(attr[i]->atttypid);
@@ -662,13 +658,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
662658
for (i = 0; i < attr_count; i++)
663659
{
664660
nulls[i] = ' ';
665-
#ifdef _DROP_COLUMN_HACK__
666-
if (COLUMN_IS_DROPPED(attr[i]))
667-
{
668-
byval[i] = 'n';
669-
continue;
670-
}
671-
#endif /* _DROP_COLUMN_HACK__ */
672661
byval[i] = IsTypeByVal(attr[i]->atttypid);
673662
}
674663

@@ -704,14 +693,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
704693
}
705694
for (i = 0; i < attr_count && !done; i++)
706695
{
707-
#ifdef _DROP_COLUMN_HACK__
708-
if (COLUMN_IS_DROPPED(attr[i]))
709-
{
710-
values[i] = PointerGetDatum(NULL);
711-
nulls[i] = 'n';
712-
continue;
713-
}
714-
#endif /* _DROP_COLUMN_HACK__ */
715696
string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print);
716697
if (isnull)
717698
{
@@ -889,22 +870,6 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
889870
}
890871

891872

892-
static Oid
893-
GetOutputFunction(Oid type)
894-
{
895-
HeapTuple typeTuple;
896-
Oid result;
897-
898-
typeTuple = SearchSysCache(TYPEOID,
899-
ObjectIdGetDatum(type),
900-
0, 0, 0);
901-
if (!HeapTupleIsValid(typeTuple))
902-
elog(ERROR, "GetOutputFunction: Cache lookup of type %u failed", type);
903-
result = ((Form_pg_type) GETSTRUCT(typeTuple))->typoutput;
904-
ReleaseSysCache(typeTuple);
905-
return result;
906-
}
907-
908873
static Oid
909874
GetInputFunction(Oid type)
910875
{

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy