88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.243 2005/05/06 17:24:53 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.244 2005/05/07 02:22:46 momjian Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -131,13 +131,13 @@ static bool line_buf_converted;
131131/* non-export function prototypes */
132132static void DoCopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
133133char * delim ,char * null_print ,bool csv_mode ,char * quote ,
134- char * escape ,List * force_quote_atts ,bool fe_copy );
134+ char * escape ,List * force_quote_atts ,bool header_line , bool fe_copy );
135135static void CopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
136136char * delim ,char * null_print ,bool csv_mode ,char * quote ,char * escape ,
137- List * force_quote_atts );
137+ List * force_quote_atts , bool header_line );
138138static void CopyFrom (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
139139char * delim ,char * null_print ,bool csv_mode ,char * quote ,char * escape ,
140- List * force_notnull_atts );
140+ List * force_notnull_atts , bool header_line );
141141static bool CopyReadLine (char * quote ,char * escape );
142142static char * CopyReadAttribute (const char * delim ,const char * null_print ,
143143CopyReadResult * result ,bool * isnull );
@@ -695,6 +695,7 @@ DoCopy(const CopyStmt *stmt)
695695bool binary = false;
696696bool oids = false;
697697bool csv_mode = false;
698+ bool header_line = false;
698699char * delim = NULL ;
699700char * quote = NULL ;
700701char * escape = NULL ;
@@ -752,6 +753,14 @@ DoCopy(const CopyStmt *stmt)
752753errmsg ("conflicting or redundant options" )));
753754csv_mode = intVal (defel -> arg );
754755}
756+ else if (strcmp (defel -> defname ,"header" )== 0 )
757+ {
758+ if (header_line )
759+ ereport (ERROR ,
760+ (errcode (ERRCODE_SYNTAX_ERROR ),
761+ errmsg ("conflicting or redundant options" )));
762+ header_line = intVal (defel -> arg );
763+ }
755764else if (strcmp (defel -> defname ,"quote" )== 0 )
756765{
757766if (quote )
@@ -825,6 +834,12 @@ DoCopy(const CopyStmt *stmt)
825834(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
826835errmsg ("COPY delimiter must be a single character" )));
827836
837+ /* Check header */
838+ if (!csv_mode && header_line )
839+ ereport (ERROR ,
840+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
841+ errmsg ("COPY HEADER available only in CSV mode" )));
842+
828843/* Check quote */
829844if (!csv_mode && quote != NULL )
830845ereport (ERROR ,
@@ -1015,7 +1030,7 @@ DoCopy(const CopyStmt *stmt)
10151030}
10161031}
10171032CopyFrom (rel ,attnumlist ,binary ,oids ,delim ,null_print ,csv_mode ,
1018- quote ,escape ,force_notnull_atts );
1033+ quote ,escape ,force_notnull_atts , header_line );
10191034}
10201035else
10211036{/* copy from database to file */
@@ -1079,7 +1094,7 @@ DoCopy(const CopyStmt *stmt)
10791094}
10801095
10811096DoCopyTo (rel ,attnumlist ,binary ,oids ,delim ,null_print ,csv_mode ,
1082- quote ,escape ,force_quote_atts ,fe_copy );
1097+ quote ,escape ,force_quote_atts ,header_line , fe_copy );
10831098}
10841099
10851100if (!pipe )
@@ -1111,15 +1126,15 @@ DoCopy(const CopyStmt *stmt)
11111126static void
11121127DoCopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
11131128char * delim ,char * null_print ,bool csv_mode ,char * quote ,
1114- char * escape ,List * force_quote_atts ,bool fe_copy )
1129+ char * escape ,List * force_quote_atts ,bool header_line , bool fe_copy )
11151130{
11161131PG_TRY ();
11171132{
11181133if (fe_copy )
11191134SendCopyBegin (binary ,list_length (attnumlist ));
11201135
11211136CopyTo (rel ,attnumlist ,binary ,oids ,delim ,null_print ,csv_mode ,
1122- quote ,escape ,force_quote_atts );
1137+ quote ,escape ,force_quote_atts , header_line );
11231138
11241139if (fe_copy )
11251140SendCopyEnd (binary );
@@ -1143,7 +1158,7 @@ DoCopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
11431158static void
11441159CopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
11451160char * delim ,char * null_print ,bool csv_mode ,char * quote ,
1146- char * escape ,List * force_quote_atts )
1161+ char * escape ,List * force_quote_atts , bool header_line )
11471162{
11481163HeapTuple tuple ;
11491164TupleDesc tupDesc ;
@@ -1226,6 +1241,30 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
12261241null_print = (char * )
12271242pg_server_to_client ((unsignedchar * )null_print ,
12281243strlen (null_print ));
1244+
1245+ /* if a header has been requested send the line */
1246+ if (header_line )
1247+ {
1248+ bool hdr_delim = false;
1249+ char * colname ;
1250+
1251+ foreach (cur ,attnumlist )
1252+ {
1253+ int attnum = lfirst_int (cur );
1254+
1255+ if (hdr_delim )
1256+ CopySendChar (delim [0 ]);
1257+ hdr_delim = true;
1258+
1259+ colname = NameStr (attr [attnum - 1 ]-> attname );
1260+
1261+ CopyAttributeOutCSV (colname ,delim ,quote ,escape ,
1262+ strcmp (colname ,null_print )== 0 );
1263+ }
1264+
1265+ CopySendEndOfRow (binary );
1266+
1267+ }
12291268}
12301269
12311270scandesc = heap_beginscan (rel ,ActiveSnapshot ,0 ,NULL );
@@ -1427,7 +1466,7 @@ limit_printout_length(StringInfo buf)
14271466static void
14281467CopyFrom (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
14291468char * delim ,char * null_print ,bool csv_mode ,char * quote ,
1430- char * escape ,List * force_notnull_atts )
1469+ char * escape ,List * force_notnull_atts , bool header_line )
14311470{
14321471HeapTuple tuple ;
14331472TupleDesc tupDesc ;
@@ -1653,6 +1692,13 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
16531692errcontext .previous = error_context_stack ;
16541693error_context_stack = & errcontext ;
16551694
1695+ /* on input just throw the header line away */
1696+ if (header_line )
1697+ {
1698+ copy_lineno ++ ;
1699+ done = CopyReadLine (quote ,escape ) ;
1700+ }
1701+
16561702while (!done )
16571703{
16581704bool skip_tuple ;