diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java index b6ded5512..453e994fe 100644 --- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java +++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java @@ -617,13 +617,19 @@ static ParsedCopyStatement parse(String sql) { } builder.direction = Direction.valueOf(parser.readKeyword().toUpperCase()); if (builder.direction == Direction.FROM) { - if (!parser.eatKeyword("stdin")) { + // Silently ignore typo 'copy from stdout'. + // See + // https://github.com/postgres/postgres/blob/03ec203164119f11f0eab4c83c97a8527e2b108d/src/backend/parser/gram.y#L3463 + if (!parser.eatKeyword("stdin") && !parser.eatKeyword("stdout")) { throw PGExceptionFactory.newPGException( "missing 'STDIN' keyword. PGAdapter only supports COPY ... FROM STDIN: " + sql, SQLState.SyntaxError); } } else { - if (!parser.eatKeyword("stdout")) { + // Silently ignore typo 'copy to stdin'. + // See + // https://github.com/postgres/postgres/blob/03ec203164119f11f0eab4c83c97a8527e2b108d/src/backend/parser/gram.y#L3463 + if (!parser.eatKeyword("stdout") && !parser.eatKeyword("stdin")) { throw PGExceptionFactory.newPGException( "missing 'STDOUT' keyword. PGAdapter only supports COPY ... TO STDOUT: " + sql, SQLState.SyntaxError); diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/CopyStatementTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/CopyStatementTest.java index 062e84b71..01d77bbfc 100644 --- a/src/test/java/com/google/cloud/spanner/pgadapter/statements/CopyStatementTest.java +++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/CopyStatementTest.java @@ -51,6 +51,14 @@ public void testParseNonCopy() { public void testParseDirection() { assertEquals(Direction.FROM, parse("copy my_table from stdin").direction); assertEquals(Direction.TO, parse("copy my_table to stdout").direction); + + // PostgreSQL accepts this kind of typo. + // See + // https://github.com/postgres/postgres/blob/03ec203164119f11f0eab4c83c97a8527e2b108d/src/backend/parser/gram.y#L3463 + assertEquals(Direction.FROM, parse("copy my_table from stdout").direction); + assertEquals(Direction.TO, parse("copy my_table to stdin").direction); + + // COPY BOTH is not supported. assertThrows(PGException.class, () -> parse("copy my_table both stdin")); }