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"
4747/* non-export function prototypes */
4848static void CopyTo (Relation rel , bool binary , bool oids , FILE * fp , char * delim , char * null_print );
4949static void CopyFrom (Relation rel , bool binary , bool oids , FILE * fp , char * delim , char * null_print );
50- static Oid GetOutputFunction (Oid type );
5150static Oid GetInputFunction (Oid type );
5251static Oid GetTypeElement (Oid type );
5352static bool IsTypeByVal (Oid type );
5453static void CopyReadNewline (FILE * fp , int * newline );
5554static char * CopyReadAttribute (FILE * fp , bool * isnull , char * delim , int * newline , char * null_print );
56-
5755static void CopyAttributeOut (FILE * fp , char * string , char * delim );
5856static 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 */
6563static 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+ */
386390static void
387391CopyTo (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+ */
574574static void
575575CopyFrom (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-
908873static Oid
909874GetInputFunction (Oid type )
910875{
0 commit comments