@@ -322,11 +322,13 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
322322}
323323
324324/*
325- * Extract a CopyHeaderChoice value from a DefElem. This is like
326- * defGetBoolean() but also accepts the special value "match".
325+ * Extract the CopyFormatOptions.header_line value from a DefElem.
326+ *
327+ * Parses the HEADER option for COPY, which can be a boolean, a non-negative
328+ * integer (number of lines to skip), or the special value "match".
327329 */
328- static CopyHeaderChoice
329- defGetCopyHeaderChoice (DefElem * def , bool is_from )
330+ static int
331+ defGetCopyHeaderOption (DefElem * def , bool is_from )
330332{
331333 /*
332334 * If no parameter value given, assume "true" is meant.
@@ -335,20 +337,27 @@ defGetCopyHeaderChoice(DefElem *def, bool is_from)
335337 return COPY_HEADER_TRUE ;
336338
337339 /*
338- * Allow 0, 1, "true", "false", "on", "off", or "match".
340+ * Allow 0, 1, "true", "false", "on", "off", a non-negative integer, or
341+ * "match".
339342 */
340343 switch (nodeTag (def -> arg ))
341344 {
342345 case T_Integer :
343- switch (intVal (def -> arg ))
344346 {
345- case 0 :
346- return COPY_HEADER_FALSE ;
347- case 1 :
348- return COPY_HEADER_TRUE ;
349- default :
350- /* otherwise, error out below */
351- break ;
347+ int ival = intVal (def -> arg );
348+
349+ if (ival < 0 )
350+ ereport (ERROR ,
351+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
352+ errmsg ("a negative integer value cannot be "
353+ "specified for %s" , def -> defname )));
354+
355+ if (!is_from && ival > 1 )
356+ ereport (ERROR ,
357+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
358+ errmsg ("cannot use multi-line header in COPY TO" )));
359+
360+ return ival ;
352361 }
353362 break ;
354363 default :
@@ -381,7 +390,8 @@ defGetCopyHeaderChoice(DefElem *def, bool is_from)
381390 }
382391 ereport (ERROR ,
383392 (errcode (ERRCODE_SYNTAX_ERROR ),
384- errmsg ("%s requires a Boolean value or \"match\"" ,
393+ errmsg ("%s requires a Boolean value, a non-negative integer, "
394+ "or the string \"match\"" ,
385395 def -> defname )));
386396 return COPY_HEADER_FALSE ; /* keep compiler quiet */
387397}
@@ -566,7 +576,7 @@ ProcessCopyOptions(ParseState *pstate,
566576 if (header_specified )
567577 errorConflictingDefElem (defel , pstate );
568578 header_specified = true;
569- opts_out -> header_line = defGetCopyHeaderChoice (defel , is_from );
579+ opts_out -> header_line = defGetCopyHeaderOption (defel , is_from );
570580 }
571581 else if (strcmp (defel -> defname , "quote" ) == 0 )
572582 {
@@ -769,7 +779,7 @@ ProcessCopyOptions(ParseState *pstate,
769779 errmsg ("COPY delimiter cannot be \"%s\"" , opts_out -> delim )));
770780
771781 /* Check header */
772- if (opts_out -> binary && opts_out -> header_line )
782+ if (opts_out -> binary && opts_out -> header_line != COPY_HEADER_FALSE )
773783 ereport (ERROR ,
774784 (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
775785 /*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
0 commit comments