|
21 | 21 | import static org.junit.Assert.assertEquals; |
22 | 22 | import static org.junit.Assert.assertFalse; |
23 | 23 | import static org.junit.Assert.assertNotNull; |
| 24 | +import static org.junit.Assert.assertSame; |
24 | 25 | import static org.junit.Assert.assertThrows; |
25 | 26 | import static org.junit.Assert.assertTrue; |
26 | 27 | import static org.junit.Assert.fail; |
|
39 | 40 | import com.google.cloud.spanner.connection.StatementResult; |
40 | 41 | import com.google.cloud.spanner.connection.StatementResult.ResultType; |
41 | 42 | import com.google.cloud.spanner.jdbc.JdbcSqlExceptionFactory.JdbcSqlExceptionImpl; |
| 43 | +import com.google.common.collect.ImmutableList; |
42 | 44 | import com.google.rpc.Code; |
43 | 45 | import java.sql.ResultSet; |
44 | 46 | import java.sql.SQLException; |
|
47 | 49 | import java.util.Arrays; |
48 | 50 | import java.util.List; |
49 | 51 | import java.util.concurrent.TimeUnit; |
| 52 | +import javax.annotation.Nullable; |
50 | 53 | import org.junit.Test; |
51 | 54 | import org.junit.runner.RunWith; |
52 | 55 | import org.junit.runners.Parameterized; |
@@ -599,4 +602,157 @@ public void testConvertUpdateCountsToSuccessNoInfo() throws SQLException { |
599 | 602 | (long) Statement.SUCCESS_NO_INFO); |
600 | 603 | } |
601 | 604 | } |
| 605 | + |
| 606 | + @Test |
| 607 | + public void testAddReturningToStatement() throws SQLException { |
| 608 | + JdbcConnection connection = mock(JdbcConnection.class); |
| 609 | + when(connection.getDialect()).thenReturn(dialect); |
| 610 | + when(connection.getParser()).thenReturn(AbstractStatementParser.getInstance(dialect)); |
| 611 | + try (JdbcStatement statement = new JdbcStatement(connection)) { |
| 612 | + assertAddReturningSame(statement, "insert into test (id, value) values (1, 'One')", null); |
| 613 | + assertAddReturningSame( |
| 614 | + statement, "insert into test (id, value) values (1, 'One')", ImmutableList.of()); |
| 615 | + assertAddReturningEquals( |
| 616 | + statement, |
| 617 | + dialect == Dialect.POSTGRESQL |
| 618 | + ? "insert into test (id, value) values (1, 'One')\nRETURNING \"id\"" |
| 619 | + : "insert into test (id, value) values (1, 'One')\nTHEN RETURN `id`", |
| 620 | + "insert into test (id, value) values (1, 'One')", |
| 621 | + ImmutableList.of("id")); |
| 622 | + assertAddReturningEquals( |
| 623 | + statement, |
| 624 | + dialect == Dialect.POSTGRESQL |
| 625 | + ? "insert into test (id, value) values (1, 'One')\nRETURNING \"id\", \"value\"" |
| 626 | + : "insert into test (id, value) values (1, 'One')\nTHEN RETURN `id`, `value`", |
| 627 | + "insert into test (id, value) values (1, 'One')", |
| 628 | + ImmutableList.of("id", "value")); |
| 629 | + assertAddReturningEquals( |
| 630 | + statement, |
| 631 | + dialect == Dialect.POSTGRESQL |
| 632 | + ? "insert into test (id, value) values (1, 'One')\nRETURNING *" |
| 633 | + : "insert into test (id, value) values (1, 'One')\nTHEN RETURN *", |
| 634 | + "insert into test (id, value) values (1, 'One')", |
| 635 | + ImmutableList.of("*")); |
| 636 | + // Requesting generated keys for a DML statement that already contains a returning clause is a |
| 637 | + // no-op. |
| 638 | + assertAddReturningSame( |
| 639 | + statement, |
| 640 | + "insert into test (id, value) values (1, 'One') " |
| 641 | + + statement.getReturningClause() |
| 642 | + + " value", |
| 643 | + ImmutableList.of("id")); |
| 644 | + // Requesting generated keys for a query is a no-op. |
| 645 | + for (ImmutableList<String> keys : |
| 646 | + ImmutableList.of( |
| 647 | + ImmutableList.of("id"), ImmutableList.of("id", "value"), ImmutableList.of("*"))) { |
| 648 | + assertAddReturningSame(statement, "select id, value from test", keys); |
| 649 | + } |
| 650 | + |
| 651 | + // Update statements may also request generated keys. |
| 652 | + assertAddReturningSame(statement, "update test set value='Two' where id=1", null); |
| 653 | + assertAddReturningSame( |
| 654 | + statement, "update test set value='Two' where id=1", ImmutableList.of()); |
| 655 | + assertAddReturningEquals( |
| 656 | + statement, |
| 657 | + dialect == Dialect.POSTGRESQL |
| 658 | + ? "update test set value='Two' where id=1\nRETURNING \"value\"" |
| 659 | + : "update test set value='Two' where id=1\nTHEN RETURN `value`", |
| 660 | + "update test set value='Two' where id=1", |
| 661 | + ImmutableList.of("value")); |
| 662 | + assertAddReturningEquals( |
| 663 | + statement, |
| 664 | + dialect == Dialect.POSTGRESQL |
| 665 | + ? "update test set value='Two' where id=1\nRETURNING \"value\", \"id\"" |
| 666 | + : "update test set value='Two' where id=1\nTHEN RETURN `value`, `id`", |
| 667 | + "update test set value='Two' where id=1", |
| 668 | + ImmutableList.of("value", "id")); |
| 669 | + assertAddReturningEquals( |
| 670 | + statement, |
| 671 | + dialect == Dialect.POSTGRESQL |
| 672 | + ? "update test set value='Two' where id=1\nRETURNING *" |
| 673 | + : "update test set value='Two' where id=1\nTHEN RETURN *", |
| 674 | + "update test set value='Two' where id=1", |
| 675 | + ImmutableList.of("*")); |
| 676 | + // Requesting generated keys for a DML statement that already contains a returning clause is a |
| 677 | + // no-op. |
| 678 | + assertAddReturningSame( |
| 679 | + statement, |
| 680 | + "update test set value='Two' where id=1 " + statement.getReturningClause() + " value", |
| 681 | + ImmutableList.of("value")); |
| 682 | + |
| 683 | + // Delete statements may also request generated keys. |
| 684 | + assertAddReturningSame(statement, "delete test where id=1", null); |
| 685 | + assertAddReturningSame(statement, "delete test where id=1", ImmutableList.of()); |
| 686 | + assertAddReturningEquals( |
| 687 | + statement, |
| 688 | + dialect == Dialect.POSTGRESQL |
| 689 | + ? "delete test where id=1\nRETURNING \"value\"" |
| 690 | + : "delete test where id=1\nTHEN RETURN `value`", |
| 691 | + "delete test where id=1", |
| 692 | + ImmutableList.of("value")); |
| 693 | + assertAddReturningEquals( |
| 694 | + statement, |
| 695 | + dialect == Dialect.POSTGRESQL |
| 696 | + ? "delete test where id=1\nRETURNING \"id\", \"value\"" |
| 697 | + : "delete test where id=1\nTHEN RETURN `id`, `value`", |
| 698 | + "delete test where id=1", |
| 699 | + ImmutableList.of("id", "value")); |
| 700 | + assertAddReturningEquals( |
| 701 | + statement, |
| 702 | + dialect == Dialect.POSTGRESQL |
| 703 | + ? "delete test where id=1\nRETURNING *" |
| 704 | + : "delete test where id=1\nTHEN RETURN *", |
| 705 | + "delete test where id=1", |
| 706 | + ImmutableList.of("*")); |
| 707 | + // Requesting generated keys for a DML statement that already contains a returning clause is a |
| 708 | + // no-op. |
| 709 | + for (ImmutableList<String> keys : |
| 710 | + ImmutableList.of( |
| 711 | + ImmutableList.of("id"), ImmutableList.of("id", "value"), ImmutableList.of("*"))) { |
| 712 | + assertAddReturningSame( |
| 713 | + statement, |
| 714 | + "delete test where id=1 " |
| 715 | + + (dialect == Dialect.POSTGRESQL |
| 716 | + ? "delete test where id=1\nRETURNING" |
| 717 | + : "delete test where id=1\nTHEN RETURN") |
| 718 | + + " value", |
| 719 | + keys); |
| 720 | + } |
| 721 | + |
| 722 | + // Requesting generated keys for DDL is a no-op. |
| 723 | + for (ImmutableList<String> keys : |
| 724 | + ImmutableList.of( |
| 725 | + ImmutableList.of("id"), ImmutableList.of("id", "value"), ImmutableList.of("*"))) { |
| 726 | + assertAddReturningSame( |
| 727 | + statement, |
| 728 | + dialect == Dialect.POSTGRESQL |
| 729 | + ? "create table test (id bigint primary key, value varchar)" |
| 730 | + : "create table test (id int64, value string(max)) primary key (id)", |
| 731 | + keys); |
| 732 | + } |
| 733 | + } |
| 734 | + } |
| 735 | + |
| 736 | + private void assertAddReturningSame( |
| 737 | + JdbcStatement statement, String sql, @Nullable ImmutableList<String> generatedKeysColumns) |
| 738 | + throws SQLException { |
| 739 | + com.google.cloud.spanner.Statement spannerStatement = |
| 740 | + com.google.cloud.spanner.Statement.of(sql); |
| 741 | + assertSame( |
| 742 | + spannerStatement, |
| 743 | + statement.addReturningToStatement(spannerStatement, generatedKeysColumns)); |
| 744 | + } |
| 745 | + |
| 746 | + private void assertAddReturningEquals( |
| 747 | + JdbcStatement statement, |
| 748 | + String expectedSql, |
| 749 | + String sql, |
| 750 | + @Nullable ImmutableList<String> generatedKeysColumns) |
| 751 | + throws SQLException { |
| 752 | + com.google.cloud.spanner.Statement spannerStatement = |
| 753 | + com.google.cloud.spanner.Statement.of(sql); |
| 754 | + assertEquals( |
| 755 | + com.google.cloud.spanner.Statement.of(expectedSql), |
| 756 | + statement.addReturningToStatement(spannerStatement, generatedKeysColumns)); |
| 757 | + } |
602 | 758 | } |
0 commit comments