Skip to content

Commit 4d80a6b

Browse files
Add support for parsing COPY statements from STDIN without a semicolon
1 parent bd7f70e commit 4d80a6b

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

src/parser/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11028,8 +11028,12 @@ impl<'a> Parser<'a> {
1102811028
legacy_options.push(opt);
1102911029
}
1103011030
let values = if let CopyTarget::Stdin = target {
11031-
self.expect_token(&Token::SemiColon)?;
11032-
self.parse_tsv()
11031+
if self.peek_token_ref().token == Token::EOF {
11032+
vec![]
11033+
} else {
11034+
self.expect_token(&Token::SemiColon)?;
11035+
self.parse_tsv()
11036+
}
1103311037
} else {
1103411038
vec![]
1103511039
};

tests/sqlparser_postgres.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,61 @@ PHP ₱ USD $
10841084
pg_and_generic().one_statement_parses_to(sql, "");
10851085
}
10861086

1087+
#[test]
1088+
fn parse_copy_from_stdin_without_semicolon() {
1089+
let stmt = pg().verified_stmt("COPY bitwise_test FROM STDIN NULL 'null'");
1090+
assert_eq!(
1091+
stmt,
1092+
Statement::Copy {
1093+
source: CopySource::Table {
1094+
table_name: ObjectName::from(vec!["bitwise_test".into()]),
1095+
columns: vec![],
1096+
},
1097+
to: false,
1098+
target: CopyTarget::Stdin,
1099+
options: vec![],
1100+
legacy_options: vec![CopyLegacyOption::Null("null".into())],
1101+
values: vec![],
1102+
}
1103+
);
1104+
}
1105+
1106+
#[test]
1107+
fn parse_copy_from_stdin_without_semicolon_variants() {
1108+
let cases = [
1109+
"COPY bool_test FROM STDIN NULL 'null'",
1110+
"COPY varbit_table FROM stdin",
1111+
"COPY bit_table FROM stdin",
1112+
"copy copytest2(test) from stdin",
1113+
"copy copytest3 from stdin csv header",
1114+
"copy copytest4 from stdin (header)",
1115+
"copy parted_copytest from stdin",
1116+
"copy tab_progress_reporting from stdin",
1117+
"copy oversized_column_default from stdin",
1118+
"COPY x (a, b, c, d, e) from stdin",
1119+
"copy header_copytest (c, a) from stdin",
1120+
"COPY atest5 (two) FROM stdin",
1121+
"COPY main_table (a, b) FROM stdin",
1122+
];
1123+
1124+
for sql in cases {
1125+
match pg().one_statement_parses_to(sql, "") {
1126+
Statement::Copy {
1127+
to: false,
1128+
target: CopyTarget::Stdin,
1129+
values,
1130+
..
1131+
} => {
1132+
assert!(
1133+
values.is_empty(),
1134+
"expected no inline COPY payload for `{sql}`"
1135+
);
1136+
}
1137+
_ => panic!("expected COPY ... FROM STDIN statement for `{sql}`"),
1138+
}
1139+
}
1140+
}
1141+
10871142
#[test]
10881143
fn test_copy_from() {
10891144
let stmt = pg().verified_stmt("COPY users FROM 'data.csv'");

0 commit comments

Comments
 (0)