Fix handling of redundant options with COPY for "freeze" and "header"
The handling of those options was inconsistent, as the processing used directly the value assigned to the option to check if it was redundant, leading to patterns like this one to succeed (note that false is specified first): COPY hoge to '/path/to/file/' (header off, header on); And the opposite would fail correctly (note that true is first here): COPY hoge to '/path/to/file/' (header on, header off); While on it, add some tests to check for all redundant patterns with the options of COPY. I have gone through the code and did not notice similar mistakes for other commands. "header" got it wrong sinceb63990c
, and "freeze" was wrong from the start as of8de72b6
. No backpatch is done per the lack of complaints. Reported-by: Rémi Lapeyre Discussion: https://postgr.es/m/20200929072433.GA15570@paquier.xyz Discussion: https://postgr.es/m/0B55BD07-83E4-439F-AACC-FA2D7CF50532@lenstra.fr
This commit is contained in:
parent
97b6144826
commit
10c5291cc2
|
@ -1159,6 +1159,8 @@ ProcessCopyOptions(ParseState *pstate,
|
|||
List *options)
|
||||
{
|
||||
bool format_specified = false;
|
||||
bool freeze_specified = false;
|
||||
bool header_specified = false;
|
||||
ListCell *option;
|
||||
|
||||
/* Support external use for option sanity checking */
|
||||
|
@ -1198,11 +1200,12 @@ ProcessCopyOptions(ParseState *pstate,
|
|||
}
|
||||
else if (strcmp(defel->defname, "freeze") == 0)
|
||||
{
|
||||
if (cstate->freeze)
|
||||
if (freeze_specified)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
freeze_specified = true;
|
||||
cstate->freeze = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "delimiter") == 0)
|
||||
|
@ -1225,11 +1228,12 @@ ProcessCopyOptions(ParseState *pstate,
|
|||
}
|
||||
else if (strcmp(defel->defname, "header") == 0)
|
||||
{
|
||||
if (cstate->header_line)
|
||||
if (header_specified)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
header_specified = true;
|
||||
cstate->header_line = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "quote") == 0)
|
||||
|
|
|
@ -28,6 +28,53 @@ COPY x (a, b, c, d, e) from stdin;
|
|||
-- non-existent column in column list: should fail
|
||||
COPY x (xyz) from stdin;
|
||||
ERROR: column "xyz" of relation "x" does not exist
|
||||
-- redundant options
|
||||
COPY x from stdin (format CSV, FORMAT CSV);
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (format CSV, FORMAT CSV);
|
||||
^
|
||||
COPY x from stdin (freeze off, freeze on);
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (freeze off, freeze on);
|
||||
^
|
||||
COPY x from stdin (delimiter ',', delimiter ',');
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (delimiter ',', delimiter ',');
|
||||
^
|
||||
COPY x from stdin (null ' ', null ' ');
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (null ' ', null ' ');
|
||||
^
|
||||
COPY x from stdin (header off, header on);
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (header off, header on);
|
||||
^
|
||||
COPY x from stdin (quote ':', quote ':');
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (quote ':', quote ':');
|
||||
^
|
||||
COPY x from stdin (escape ':', escape ':');
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (escape ':', escape ':');
|
||||
^
|
||||
COPY x from stdin (force_quote (a), force_quote *);
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (force_quote (a), force_quote *);
|
||||
^
|
||||
COPY x from stdin (force_not_null (a), force_not_null (b));
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (force_not_null (a), force_not_null (b));
|
||||
^
|
||||
COPY x from stdin (force_null (a), force_null (b));
|
||||
ERROR: conflicting or redundant options
|
||||
COPY x from stdin (convert_selectively (a), convert_selectively (b));
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (convert_selectively (a), convert_selectiv...
|
||||
^
|
||||
COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
|
||||
ERROR: conflicting or redundant options
|
||||
LINE 1: COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii...
|
||||
^
|
||||
-- too many columns in column list: should fail
|
||||
COPY x (a, b, c, d, e, d, c) from stdin;
|
||||
ERROR: column "d" specified more than once
|
||||
|
|
|
@ -53,6 +53,20 @@ COPY x (a, b, c, d, e) from stdin;
|
|||
-- non-existent column in column list: should fail
|
||||
COPY x (xyz) from stdin;
|
||||
|
||||
-- redundant options
|
||||
COPY x from stdin (format CSV, FORMAT CSV);
|
||||
COPY x from stdin (freeze off, freeze on);
|
||||
COPY x from stdin (delimiter ',', delimiter ',');
|
||||
COPY x from stdin (null ' ', null ' ');
|
||||
COPY x from stdin (header off, header on);
|
||||
COPY x from stdin (quote ':', quote ':');
|
||||
COPY x from stdin (escape ':', escape ':');
|
||||
COPY x from stdin (force_quote (a), force_quote *);
|
||||
COPY x from stdin (force_not_null (a), force_not_null (b));
|
||||
COPY x from stdin (force_null (a), force_null (b));
|
||||
COPY x from stdin (convert_selectively (a), convert_selectively (b));
|
||||
COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
|
||||
|
||||
-- too many columns in column list: should fail
|
||||
COPY x (a, b, c, d, e, d, c) from stdin;
|
||||
|
||||
|
|
Loading…
Reference in New Issue