diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/ITAbstractJdbcTest.java b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/ITAbstractJdbcTest.java index 1793a618e878..f02eb7704969 100644 --- a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/ITAbstractJdbcTest.java +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/ITAbstractJdbcTest.java @@ -87,8 +87,12 @@ public static void setup() throws IOException, InterruptedException, ExecutionEx * @return The newly opened JDBC connection. */ public CloudSpannerJdbcConnection createConnection() throws SQLException { - StringBuilder url = - new StringBuilder("jdbc:cloudspanner:/").append(getDatabase().getId().getName()); + StringBuilder url = new StringBuilder("jdbc:cloudspanner:"); + String host = env.getTestHelper().getOptions().getHost(); + if (host != null) { + url.append(host.substring(host.indexOf(':') + 1)); + } + url.append("/").append(getDatabase().getId().getName()); if (hasValidKeyFile()) { url.append(";credentials=").append(getKeyFile()); } diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java new file mode 100644 index 000000000000..40b17452d842 --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java @@ -0,0 +1,941 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.jdbc.it; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import com.google.api.client.util.Base64; +import com.google.cloud.spanner.IntegrationTest; +import com.google.cloud.spanner.jdbc.ITAbstractJdbcTest; +import com.google.common.base.Strings; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.StringReader; +import java.sql.BatchUpdateException; +import java.sql.Connection; +import java.sql.Date; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Scanner; +import java.util.TimeZone; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.junit.runners.MethodSorters; + +/** Integration tests for JDBC {@link PreparedStatement}s. */ +@Category(IntegrationTest.class) +@RunWith(JUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ITJdbcPreparedStatementTest extends ITAbstractJdbcTest { + private static final class Singer { + private final long singerId; + private final String firstName; + private final String lastName; + private final byte[] singerInfo; + private final Date birthDate; + + private static Singer of(String values) { + String[] array = values.split(","); + if (array.length != 5) { + throw new IllegalArgumentException(values); + } + return new Singer( + Long.valueOf(array[0]), // singer id + array[1].substring(1, array[1].length() - 1), // first name + array[2].substring(1, array[2].length() - 1), // last name + parseBytes(array[3].substring(13, array[3].length() - 2)), // singer info + parseDate(array[4].substring(6, array[4].length() - 1)) // birth date + ); + } + + private Singer( + long singerId, String firstName, String lastName, byte[] singerInfo, Date birthDate) { + this.singerId = singerId; + this.firstName = firstName; + this.lastName = lastName; + this.singerInfo = singerInfo; + this.birthDate = birthDate; + } + } + + private static final class Album { + private final long singerId; + private final long albumId; + private final String albumTitle; + private final long marketingBudget; + + private static Album of(String values) { + String[] array = values.split(","); + if (array.length != 4) { + throw new IllegalArgumentException(values); + } + return new Album( + Long.valueOf(array[0]), // singer id + Long.valueOf(array[1]), // album id + array[2].substring(1, array[2].length() - 1), // album title + Long.valueOf(array[3]) // marketing budget + ); + } + + private Album(long singerId, long albumId, String albumTitle, long marketingBudget) { + this.singerId = singerId; + this.albumId = albumId; + this.albumTitle = albumTitle; + this.marketingBudget = marketingBudget; + } + } + + private static final class Song { + private final long singerId; + private final long albumId; + private final long songId; + private final String songName; + private final long duration; + private final String songGenre; + + private static Song of(String values) { + String[] array = values.split(","); + if (array.length != 6) { + throw new IllegalArgumentException(values); + } + return new Song( + Long.valueOf(array[0]), // singer id + Long.valueOf(array[1]), // album id + Long.valueOf(array[2]), // song id + array[3].substring(1, array[3].length() - 1), // song name + Long.valueOf(array[4]), // duration + array[5].substring(1, array[5].length() - 1)); + } + + private Song( + long singerId, + long albumId, + long songId, + String songName, + long duration, + String songGenre) { + this.singerId = singerId; + this.albumId = albumId; + this.songId = songId; + this.songName = songName; + this.duration = duration; + this.songGenre = songGenre; + } + } + + private static final class Concert { + private final long venueId; + private final long singerId; + private final Date concertDate; + private final Timestamp beginTime; + private final Timestamp endTime; + private final Long[] ticketPrices; + + private static Concert of(String values) { + values = values.replaceAll("\\[(\\d+),(\\d+),(\\d+),(\\d+)\\]", "[$1;$2;$3;$4]"); + String[] array = values.split(","); + if (array.length != 6) { + throw new IllegalArgumentException(values); + } + return new Concert( + Long.valueOf(array[0]), // venue id + Long.valueOf(array[1]), // singer id + parseDate(array[2].substring(6, array[2].length() - 1)), // concert date + parseTimestamp(array[3].substring(11, array[3].length() - 1)), // begin time + parseTimestamp(array[4].substring(11, array[4].length() - 1)), // end time + parseLongArray(array[5]) // ticket prices + ); + } + + private Concert( + long venueId, + long singerId, + Date concertDate, + Timestamp beginTime, + Timestamp endTime, + Long[] ticketPrices) { + this.venueId = venueId; + this.singerId = singerId; + this.concertDate = concertDate; + this.beginTime = beginTime; + this.endTime = endTime; + this.ticketPrices = ticketPrices; + } + } + + private static Date parseDate(String value) { + try { + return Date.valueOf(value); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(value); + } + } + + private static Timestamp parseTimestamp(String value) { + try { + return Timestamp.valueOf(value.replace('T', ' ').replace("Z", "")); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(value); + } + } + + private static Long[] parseLongArray(String value) { + String[] values = value.substring(1, value.length() - 1).split(";"); + Long[] res = new Long[values.length]; + for (int index = 0; index < values.length; index++) { + res[index] = Long.valueOf(values[index]); + } + return res; + } + + private static byte[] parseBytes(String value) { + return Base64.decodeBase64(value); + } + + private List createSingers() { + List res = new ArrayList<>(); + for (String singerValue : readValuesFromFile("Singers.txt")) { + res.add(Singer.of(singerValue)); + } + return res; + } + + private List createAlbums() { + List res = new ArrayList<>(); + for (String albumValue : readValuesFromFile("Albums.txt")) { + res.add(Album.of(albumValue)); + } + return res; + } + + private List createSongs() { + List res = new ArrayList<>(); + for (String songValue : readValuesFromFile("Songs.txt")) { + res.add(Song.of(songValue)); + } + return res; + } + + private List createConcerts() { + List res = new ArrayList<>(); + for (String concertValue : readValuesFromFile("Concerts.txt")) { + res.add(Concert.of(concertValue)); + } + return res; + } + + @Override + protected boolean doCreateMusicTables() { + return true; + } + + @Test + public void test01_InsertTestData() throws SQLException { + try (Connection connection = createConnection()) { + connection.setAutoCommit(false); + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, BirthDate) values (?,?,?,?,?)")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 5); + for (Singer singer : createSingers()) { + ps.setByte(1, (byte) singer.singerId); + ps.setString(2, singer.firstName); + ps.setString(3, singer.lastName); + ps.setBytes(4, singer.singerInfo); + ps.setDate(5, singer.birthDate); + + assertInsertSingerParameterMetadata(ps.getParameterMetaData()); + ps.addBatch(); + // check that adding the current params to a batch will not reset the meta data + assertInsertSingerParameterMetadata(ps.getParameterMetaData()); + } + int[] results = ps.executeBatch(); + for (int res : results) { + assertThat(res, is(equalTo(1))); + } + } + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Albums (SingerId, AlbumId, AlbumTitle, MarketingBudget) VALUES (?,?,?,?)")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 4); + for (Album album : createAlbums()) { + ps.setLong(1, album.singerId); + ps.setLong(2, album.albumId); + ps.setString(3, album.albumTitle); + ps.setLong(4, album.marketingBudget); + assertInsertAlbumParameterMetadata(ps.getParameterMetaData()); + assertThat(ps.executeUpdate(), is(equalTo(1))); + // check that calling executeUpdate will not reset the meta data + assertInsertAlbumParameterMetadata(ps.getParameterMetaData()); + } + } + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre) VALUES (?,?,?,?,?,?);")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 6); + for (Song song : createSongs()) { + ps.setByte(1, (byte) song.singerId); + ps.setInt(2, (int) song.albumId); + ps.setShort(3, (short) song.songId); + ps.setNString(4, song.songName); + ps.setLong(5, song.duration); + ps.setCharacterStream(6, new StringReader(song.songGenre)); + assertInsertSongParameterMetadata(ps.getParameterMetaData()); + assertThat(ps.executeUpdate(), is(equalTo(1))); + // check that calling executeUpdate will not reset the meta data + assertInsertSongParameterMetadata(ps.getParameterMetaData()); + } + } + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Concerts (VenueId, SingerId, ConcertDate, BeginTime, EndTime, TicketPrices) VALUES (?,?,?,?,?,?);")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 6); + for (Concert concert : createConcerts()) { + ps.setLong(1, concert.venueId); + ps.setLong(2, concert.singerId); + ps.setDate(3, concert.concertDate); + ps.setTimestamp(4, concert.beginTime); + ps.setTimestamp(5, concert.endTime); + ps.setArray(6, connection.createArrayOf("INT64", concert.ticketPrices)); + assertInsertConcertParameterMetadata(ps.getParameterMetaData()); + assertThat(ps.executeUpdate(), is(equalTo(1))); + // check that calling executeUpdate will not reset the meta data + assertInsertConcertParameterMetadata(ps.getParameterMetaData()); + } + } + connection.commit(); + } + } + + @Test + public void test02_VerifyTestData() throws SQLException { + try (Connection connection = createConnection()) { + try (ResultSet rs = + connection.createStatement().executeQuery("SELECT COUNT(*) FROM Singers")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getInt(1), is(equalTo(30))); + assertThat(rs.next(), is(false)); + } + try (ResultSet rs = + connection.createStatement().executeQuery("SELECT COUNT(*) FROM Albums")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getByte(1), is(equalTo((byte) 60))); + assertThat(rs.next(), is(false)); + } + try (ResultSet rs = connection.createStatement().executeQuery("SELECT COUNT(*) FROM Songs")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getShort(1), is(equalTo((short) 149))); + assertThat(rs.next(), is(false)); + } + try (ResultSet rs = + connection.createStatement().executeQuery("SELECT COUNT(*) FROM Concerts")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(100L))); + assertThat(rs.next(), is(false)); + } + try (PreparedStatement ps = + connection.prepareStatement("SELECT * FROM Concerts WHERE VenueId=? AND SingerId=?")) { + ps.setLong(1, 1L); + ps.setLong(2, 1L); + // Expected: + // (1,1,DATE '2003-06-19',TIMESTAMP '2003-06-19T12:30:05Z',TIMESTAMP + // '2003-06-19T18:57:15Z',[11,93,140,923]); + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(1L))); + assertThat(rs.getLong(2), is(equalTo(1L))); + assertThat(rs.getDate(3), is(equalTo(Date.valueOf("2003-06-19")))); + assertThat(rs.getTimestamp(4), is(equalTo(Timestamp.valueOf("2003-06-19 12:30:05")))); + assertThat(rs.getTimestamp(5), is(equalTo(Timestamp.valueOf("2003-06-19 18:57:15")))); + assertThat(((Long[]) rs.getArray(6).getArray())[0], is(equalTo(11L))); + } + } + } + } + + @SuppressWarnings("deprecation") + @Test + public void test03_Dates() throws SQLException { + List expectedValues = new ArrayList<>(); + expectedValues.add("2008-01-01"); + expectedValues.add("2000-01-01"); + expectedValues.add("1900-01-01"); + expectedValues.add("2000-02-29"); + expectedValues.add("2004-02-29"); + expectedValues.add("2018-12-31"); + expectedValues.add("2015-11-15"); + expectedValues.add("2015-11-15"); + expectedValues.add("2015-11-15"); + + List testDates = new ArrayList<>(); + testDates.add(Date.valueOf("2008-01-01")); + testDates.add(Date.valueOf("2000-01-01")); + testDates.add(Date.valueOf("1900-01-01")); + testDates.add(Date.valueOf("2000-02-29")); + testDates.add(Date.valueOf("2004-02-29")); + testDates.add(Date.valueOf("2018-12-31")); + + // Cloud Spanner does not store any timezone information, meaning that it shouldn't matter in + // what timezone a date is sent to Cloud Spanner, the same date in the local timezone (or the + // requested timezone) should be returned. + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.clear(); + cal.set(2015, 10, 15, 10, 0, 0); + testDates.add(new Date(cal.getTimeInMillis())); + + cal = Calendar.getInstance(TimeZone.getTimeZone("CET")); + cal.clear(); + cal.set(2015, 10, 15, 10, 0, 0); + testDates.add(new Date(cal.getTimeInMillis())); + + cal = Calendar.getInstance(TimeZone.getTimeZone("PST")); + cal.clear(); + cal.set(2015, 10, 15, 10, 0, 0); + testDates.add(new Date(cal.getTimeInMillis())); + + List calendars = new ArrayList<>(); + calendars.add(null); + calendars.add(Calendar.getInstance()); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("CET"))); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("PST"))); + + try (Connection connection = createConnection()) { + for (Calendar testCalendar : calendars) { + int index = 0; + for (Date testDate : testDates) { + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Concerts (VenueId, SingerId, ConcertDate, BeginTime, EndTime, TicketPrices) VALUES (?,?,?,?,?,?);")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 6); + ps.setLong(1, 100); + ps.setLong(2, 19); + ps.setDate(3, testDate); + ps.setTimestamp(4, new Timestamp(System.currentTimeMillis())); + ps.setTimestamp(5, new Timestamp(System.currentTimeMillis())); + ps.setArray(6, connection.createArrayOf("INT64", new Long[] {})); + ps.executeUpdate(); + } + + try (PreparedStatement ps = + connection.prepareStatement( + "SELECT * FROM Concerts WHERE VenueId=? AND SingerId=?")) { + ps.setLong(1, 100L); + ps.setLong(2, 19L); + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + if (testCalendar == null) { + assertThat(rs.getDate(3), is(equalTo(Date.valueOf(expectedValues.get(index))))); + } else { + // Parse the date in the local timezone. + Date date = Date.valueOf(expectedValues.get(index)); + // Create a calendar in the test timezone with only the date part set. + Calendar localCalendar = Calendar.getInstance(testCalendar.getTimeZone()); + localCalendar.clear(); + localCalendar.set(date.getYear() + 1900, date.getMonth(), date.getDate()); + // Check that the actual time of the date returned by the ResultSet is equal to the + // local time in the timezone of the Calendar that is used. + assertThat( + rs.getDate(3, testCalendar), + is(equalTo(new Date(localCalendar.getTimeInMillis())))); + } + } + } + connection + .createStatement() + .execute("DELETE FROM Concerts WHERE VenueId=100 AND SingerId=19"); + index++; + } + } + } + } + + @Test + public void test04_Timestamps() throws SQLException { + List expectedValues = new ArrayList<>(); + expectedValues.add("2008-01-01 10:00:00"); + expectedValues.add("2000-01-01 00:00:00"); + expectedValues.add("1900-01-01 12:13:14"); + expectedValues.add("2000-02-29 02:00:00"); + expectedValues.add("2004-02-29 03:00:00"); + expectedValues.add("2018-12-31 23:59:59"); + expectedValues.add("2015-11-15 10:00:00"); + expectedValues.add("2015-11-15 10:00:00"); + expectedValues.add("2015-11-15 10:00:00"); + + List timezones = new ArrayList<>(); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getDefault()); + timezones.add(TimeZone.getTimeZone("UTC")); + timezones.add(TimeZone.getTimeZone("CET")); + timezones.add(TimeZone.getTimeZone("PST")); + + List testTimestamps = new ArrayList<>(); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(0))); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(1))); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(2))); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(3))); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(4))); + testTimestamps.add(Timestamp.valueOf(expectedValues.get(5))); + + // Cloud Spanner does not store any timezone information, but does store the timestamp in UTC + // format. + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.clear(); + cal.set(2015, 10, 15); + testTimestamps.add(new Timestamp(cal.getTimeInMillis())); + + cal = Calendar.getInstance(TimeZone.getTimeZone("CET")); + cal.clear(); + cal.set(2015, 10, 15); + testTimestamps.add(new Timestamp(cal.getTimeInMillis())); + + cal = Calendar.getInstance(TimeZone.getTimeZone("PST")); + cal.clear(); + cal.set(2015, 10, 15); + testTimestamps.add(new Timestamp(cal.getTimeInMillis())); + + List calendars = new ArrayList<>(); + calendars.add(null); + calendars.add(Calendar.getInstance()); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("CET"))); + calendars.add(Calendar.getInstance(TimeZone.getTimeZone("PST"))); + + try (Connection connection = createConnection()) { + for (Calendar testCalendar : calendars) { + for (Timestamp testTimestamp : testTimestamps) { + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Concerts (VenueId, SingerId, ConcertDate, BeginTime, EndTime, TicketPrices) VALUES (?,?,?,?,?,?);")) { + assertDefaultParameterMetaData(ps.getParameterMetaData(), 6); + ps.setLong(1, 100); + ps.setLong(2, 19); + ps.setDate(3, new Date(System.currentTimeMillis())); + // Cloud Spanner will store the timestamp in UTC and no other timezone information. + ps.setTimestamp(4, testTimestamp); + ps.setTimestamp(5, testTimestamp, testCalendar); + ps.setArray(6, connection.createArrayOf("INT64", new Long[] {})); + ps.executeUpdate(); + } + + try (PreparedStatement ps = + connection.prepareStatement( + "SELECT * FROM Concerts WHERE VenueId=? AND SingerId=?")) { + ps.setLong(1, 100L); + ps.setLong(2, 19L); + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + + // First test the timestamp that was sent to Spanner using the default timezone. + // Get the timestamp in the default timezone. + Timestamp inDefaultTZ = rs.getTimestamp(4); + assertThat(inDefaultTZ.getTime(), is(equalTo(testTimestamp.getTime()))); + // Then get it in the test timezone. + if (testCalendar != null) { + Timestamp inOtherTZ = rs.getTimestamp(4, testCalendar); + assertThat( + inOtherTZ.getTime(), + is( + equalTo( + testTimestamp.getTime() + testCalendar.getTimeZone().getRawOffset()))); + } + + // Then test the timestamp that was sent to Spanner using a specific timezone. + // Get the timestamp in the default timezone. + inDefaultTZ = rs.getTimestamp(5); + if (testCalendar == null) { + assertThat(inDefaultTZ.getTime(), is(equalTo(testTimestamp.getTime()))); + } else { + assertThat( + inDefaultTZ.getTime(), + is( + equalTo( + testTimestamp.getTime() - testCalendar.getTimeZone().getRawOffset()))); + } + // Then get it in the test timezone. + if (testCalendar != null) { + Timestamp inOtherTZ = rs.getTimestamp(5, testCalendar); + assertThat(inOtherTZ.getTime(), is(equalTo(testTimestamp.getTime()))); + } + } + } + connection + .createStatement() + .execute("DELETE FROM Concerts WHERE VenueId=100 AND SingerId=19"); + } + } + } + } + + @Test + public void test05_BatchUpdates() throws SQLException { + for (boolean autocommit : new boolean[] {true, false}) { + try (Connection con1 = createConnection(); + Connection con2 = createConnection()) { + con1.setAutoCommit(autocommit); + int[] updateCounts; + String[] params = new String[] {"A%", "B%", "C%"}; + try (PreparedStatement ps = + con1.prepareStatement("UPDATE Singers SET FirstName=LastName WHERE LastName LIKE ?")) { + for (String param : params) { + ps.setString(1, param); + ps.addBatch(); + } + updateCounts = ps.executeBatch(); + } + assertThat(updateCounts.length, is(equalTo(params.length))); + long totalUpdated = 0; + try (PreparedStatement ps = + con1.prepareStatement("SELECT COUNT(*) FROM Singers WHERE LastName LIKE ?")) { + for (int i = 0; i < updateCounts.length; i++) { + ps.setString(1, params[i]); + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + assertThat(updateCounts[i], is(equalTo(rs.getInt(1)))); + totalUpdated += updateCounts[i]; + } + } + } + // Check whether the updated values are readable on the second connection. + try (ResultSet rs = + con2.createStatement() + .executeQuery("SELECT COUNT(*) FROM Singers WHERE FirstName=LastName")) { + assertThat(rs.next(), is(true)); + if (autocommit) { + assertThat(rs.getLong(1), is(equalTo(totalUpdated))); + } else { + assertThat(rs.getLong(1), is(equalTo(0L))); + } + } + // If not in autocommit mode --> commit and verify. + if (!autocommit) { + con1.commit(); + try (ResultSet rs = + con2.createStatement() + .executeQuery("SELECT COUNT(*) FROM Singers WHERE FirstName=LastName")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(totalUpdated))); + } + } + // Set first names to null for the updated records for the next test run. + assertThat( + con2.createStatement() + .executeUpdate("UPDATE Singers SET FirstName=null WHERE FirstName=LastName"), + is(equalTo((int) totalUpdated))); + } + } + } + + @Test + public void test06_BatchUpdatesWithException() throws SQLException { + for (boolean autocommit : new boolean[] {true, false}) { + try (Connection con1 = createConnection(); + Connection con2 = createConnection()) { + con1.setAutoCommit(autocommit); + String[] params = new String[] {"A%", "B%", "C%", "D%"}; + // Statement number three will fail because the value is too long for the column. + int[] updateValues = new int[] {1, 1, 1024, 1}; + try (PreparedStatement ps = + con1.prepareStatement("UPDATE Singers SET FirstName=? WHERE LastName LIKE ?")) { + for (int i = 0; i < params.length; i++) { + ps.setString(1, Strings.repeat("not too long", updateValues[i])); + ps.setString(2, params[i]); + ps.addBatch(); + } + ps.executeBatch(); + fail("missing expected BatchUpdateException"); + } catch (BatchUpdateException e) { + assertThat(e.getUpdateCounts().length, is(equalTo(2))); + } + // If not in autocommit mode --> rollback before the next run. + if (!autocommit) { + con1.rollback(); + } + // Set first names to null for the updated records for the next test run. + try (PreparedStatement ps = + con2.prepareStatement("UPDATE Singers SET FirstName=null WHERE FirstName=?")) { + ps.setString(1, "not too long"); + } + } + } + } + + @Test + public void test07_StatementBatchUpdateWithException() throws SQLException { + try (Connection con = createConnection()) { + // The following statements will fail because the value is too long. + try (Statement statement = con.createStatement()) { + statement.addBatch( + String.format( + "UPDATE Singers SET FirstName='%s' WHERE LastName LIKE 'A%%'", + Strings.repeat("too long", 1024))); + statement.addBatch( + String.format( + "UPDATE Singers SET FirstName='%s' WHERE LastName LIKE 'B%%'", + Strings.repeat("too long", 1024))); + statement.executeBatch(); + fail("missing expected BatchUpdateException"); + } catch (BatchUpdateException e) { + assertThat(e.getUpdateCounts(), is(notNullValue())); + } + // The following statements will fail because the table does not exist. + try (Statement statement = con.createStatement()) { + statement.addBatch( + String.format( + "UPDATE Non_Existent_Table SET FirstName='%s' WHERE LastName LIKE 'A%%'", + Strings.repeat("too long", 1024))); + statement.addBatch( + String.format( + "UPDATE Non_Existent_Table SET FirstName='%s' WHERE LastName LIKE 'B%%'", + Strings.repeat("too long", 1024))); + statement.executeBatch(); + fail(); + } catch (BatchUpdateException e) { + assertThat(e.getUpdateCounts(), is(notNullValue())); + } + // The following statements will fail because the primary key values conflict. + try (Statement statement = con.createStatement()) { + statement.addBatch( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, BirthDate) VALUES (9999, 'Test', 'Test', NULL, NULL)"); + statement.addBatch( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, BirthDate) VALUES (9999, 'Test', 'Test', NULL, NULL)"); + statement.executeBatch(); + fail(); + } catch (BatchUpdateException e) { + assertThat(e.getUpdateCounts(), is(notNullValue())); + } + } + } + + private void assertDefaultParameterMetaData(ParameterMetaData pmd, int expectedParamCount) + throws SQLException { + assertThat(pmd.getParameterCount(), is(equalTo(expectedParamCount))); + for (int param = 1; param <= expectedParamCount; param++) { + assertThat(pmd.getParameterType(param), is(equalTo(Types.OTHER))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("OTHER"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(nullValue())); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + } + + private List readValuesFromFile(String filename) { + File file = new File(getClass().getResource(filename).getFile()); + StringBuilder builder = new StringBuilder(); + try (Scanner scanner = new Scanner(file)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + builder.append(line).append("\n"); + } + scanner.close(); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + String[] array = builder.toString().split(";"); + List res = new ArrayList<>(array.length); + for (String statement : array) { + if (statement != null && statement.trim().length() > 0) { + // strip the ( and ) + res.add(statement.trim().substring(1, statement.trim().length() - 1)); + } + } + return res; + } + + private void assertInsertSingerParameterMetadata(ParameterMetaData pmd) throws SQLException { + assertThat(pmd.getParameterCount(), is(equalTo(5))); + assertByteParam(pmd, 1); + assertStringParam(pmd, 2); + assertStringParam(pmd, 3); + assertBytesParam(pmd, 4); + assertDateParam(pmd, 5); + } + + private void assertInsertAlbumParameterMetadata(ParameterMetaData pmd) throws SQLException { + assertThat(pmd.getParameterCount(), is(equalTo(4))); + assertLongParam(pmd, 1); + assertLongParam(pmd, 2); + assertStringParam(pmd, 3); + assertLongParam(pmd, 4); + } + + private void assertInsertSongParameterMetadata(ParameterMetaData pmd) throws SQLException { + assertThat(pmd.getParameterCount(), is(equalTo(6))); + assertByteParam(pmd, 1); + assertIntParam(pmd, 2); + assertShortParam(pmd, 3); + assertNStringParam(pmd, 4); + assertLongParam(pmd, 5); + assertStringReaderParam(pmd, 6); + } + + private void assertInsertConcertParameterMetadata(ParameterMetaData pmd) throws SQLException { + assertThat(pmd.getParameterCount(), is(equalTo(6))); + assertLongParam(pmd, 1); + assertLongParam(pmd, 2); + assertDateParam(pmd, 3); + assertTimestampParam(pmd, 4); + assertTimestampParam(pmd, 5); + assertLongArrayParam(pmd, 6); + } + + private void assertLongParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.BIGINT))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("INT64"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Long.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(true)); + } + + private void assertIntParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.INTEGER))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("INT64"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Integer.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(true)); + } + + private void assertShortParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.SMALLINT))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("INT64"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Short.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(true)); + } + + private void assertByteParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.TINYINT))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("INT64"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Byte.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(true)); + } + + private void assertStringParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.NVARCHAR))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("STRING"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(String.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertNStringParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.NVARCHAR))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("STRING"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(String.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertStringReaderParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.NVARCHAR))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("STRING"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(StringReader.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertBytesParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.BINARY))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("BYTES"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(byte[].class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertDateParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.DATE))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("DATE"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Date.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertTimestampParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.TIMESTAMP))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("TIMESTAMP"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat(pmd.getParameterClassName(param), is(equalTo(Timestamp.class.getName()))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } + + private void assertLongArrayParam(ParameterMetaData pmd, int param) throws SQLException { + assertThat(pmd.getParameterType(param), is(equalTo(Types.ARRAY))); + assertThat(pmd.getParameterTypeName(param), is(equalTo("ARRAY"))); + assertThat(pmd.getPrecision(param), is(equalTo(0))); + assertThat(pmd.getScale(param), is(equalTo(0))); + assertThat( + pmd.getParameterClassName(param), is(equalTo("com.google.cloud.spanner.jdbc.JdbcArray"))); + assertThat(pmd.getParameterMode(param), is(equalTo(ParameterMetaData.parameterModeIn))); + assertThat(pmd.isNullable(param), is(equalTo(ParameterMetaData.parameterNullableUnknown))); + assertThat(pmd.isSigned(param), is(false)); + } +} diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSimpleStatementsTest.java b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSimpleStatementsTest.java new file mode 100644 index 000000000000..4a71bfd5c358 --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcSimpleStatementsTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.jdbc.it; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import com.google.cloud.spanner.IntegrationTest; +import com.google.cloud.spanner.jdbc.ITAbstractJdbcTest; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test executing simple statements through JDBC. */ +@RunWith(JUnit4.class) +@Category(IntegrationTest.class) +public class ITJdbcSimpleStatementsTest extends ITAbstractJdbcTest { + @Rule public final ExpectedException expected = ExpectedException.none(); + + @Test + public void testSelect1() throws SQLException { + try (Connection connection = createConnection()) { + try (ResultSet rs = connection.createStatement().executeQuery("select 1")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getInt(1), is(equalTo(1))); + assertThat(rs.next(), is(false)); + } + } + } + + @Test + public void testSelect1PreparedStatement() throws SQLException { + try (Connection connection = createConnection()) { + try (PreparedStatement ps = connection.prepareStatement("select 1")) { + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + assertThat(rs.getInt(1), is(equalTo(1))); + assertThat(rs.next(), is(false)); + } + } + } + } + + @Test + public void testPreparedStatement() throws SQLException { + String sql = + "select * from (select 1 as number union all select 2 union all select 3) numbers where number=?"; + try (Connection connection = createConnection()) { + try (PreparedStatement ps = connection.prepareStatement(sql)) { + for (int i = 1; i <= 3; i++) { + ps.setInt(1, i); + try (ResultSet rs = ps.executeQuery()) { + assertThat(rs.next(), is(true)); + assertThat(rs.getInt(1), is(equalTo(i))); + assertThat(rs.next(), is(false)); + } + } + } + } + } + + @Test + public void testBatchedDdlStatements() throws SQLException { + // Execute a successful batch of DDL statements. + try (Connection connection = createConnection()) { + try (Statement statement = connection.createStatement()) { + statement.addBatch( + "CREATE TABLE FOO1 (ID INT64 NOT NULL, NAME STRING(100)) PRIMARY KEY (ID)"); + statement.addBatch( + "CREATE TABLE FOO2 (ID INT64 NOT NULL, NAME STRING(100)) PRIMARY KEY (ID)"); + int[] updateCounts = statement.executeBatch(); + assertThat( + updateCounts, + is(equalTo(new int[] {Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}))); + } + try (ResultSet rs = + connection + .createStatement() + .executeQuery( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='' AND TABLE_NAME LIKE 'FOO%'")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(2L))); + } + } + // Execute a batch of DDL statements that contains a statement that will fail. + try (Connection connection = createConnection()) { + // First create a couple of test records that will cause the index creation to fail. + try (Statement statement = connection.createStatement()) { + statement.executeUpdate("INSERT INTO FOO1 (ID, NAME) VALUES (1,'TEST')"); + statement.executeUpdate("INSERT INTO FOO1 (ID, NAME) VALUES (2,'TEST')"); + } + boolean gotExpectedException = false; + try (Statement statement = connection.createStatement()) { + statement.addBatch( + "CREATE TABLE FOO3 (ID INT64 NOT NULL, NAME STRING(100)) PRIMARY KEY (ID)"); + statement.addBatch("CREATE UNIQUE INDEX IDX_FOO1_UNIQUE ON FOO1 (NAME)"); + statement.executeBatch(); + } catch (SQLException e) { + gotExpectedException = true; + } + assertThat(gotExpectedException, is(true)); + // The table should have been created, the index should not. + try (ResultSet rs = + connection + .createStatement() + .executeQuery( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='' AND TABLE_NAME LIKE 'FOO%'")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(3L))); + } + try (ResultSet rs = + connection + .createStatement() + .executeQuery( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.INDEXES WHERE TABLE_SCHEMA='' AND INDEX_NAME='IDX_FOO1_UNIQUE'")) { + assertThat(rs.next(), is(true)); + assertThat(rs.getLong(1), is(equalTo(0L))); + } + } + } + + @Test + public void testAddBatchWhenAlreadyInBatch() throws SQLException { + expected.expect(SQLException.class); + expected.expectMessage( + "Calling addBatch() is not allowed when a DML or DDL batch has been started on the connection."); + try (Connection connection = createConnection()) { + connection.createStatement().execute("START BATCH DML"); + connection.createStatement().addBatch("INSERT INTO Singers (SingerId) VALUES (-1)"); + } + } +} diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Albums.txt b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Albums.txt new file mode 100644 index 000000000000..0cf7eafedf85 --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Albums.txt @@ -0,0 +1,60 @@ +(1,1,"Album 1",980045); +(2,2,"Album 2",667788); +(3,3,"Album 3",908791); +(4,4,"Album 4",690335); +(5,5,"Album 5",133041); +(6,6,"Album 6",505292); +(7,7,"Album 7",91969); +(8,8,"Album 8",289965); +(9,9,"Album 9",78176); +(10,10,"Album 10",485664); +(11,11,"Album 11",972680); +(12,12,"Album 12",893680); +(13,13,"Album 13",892138); +(14,14,"Album 14",449562); +(15,15,"Album 15",150968); +(16,16,"Album 16",580377); +(17,17,"Album 17",763081); +(18,18,"Album 18",203427); +(19,19,"Album 19",995368); +(20,20,"Album 20",29900); +(21,21,"Album 21",723728); +(22,22,"Album 22",540582); +(23,23,"Album 23",784245); +(24,24,"Album 24",614788); +(25,25,"Album 25",275649); +(26,26,"Album 26",970898); +(27,27,"Album 27",409289); +(28,28,"Album 28",766560); +(29,29,"Album 29",32414); +(30,30,"Album 30",457957); +(1,31,"Album 31",52546); +(2,32,"Album 32",412424); +(3,33,"Album 33",568496); +(4,34,"Album 34",353491); +(5,35,"Album 35",489951); +(6,36,"Album 36",75938); +(7,37,"Album 37",460461); +(8,38,"Album 38",642042); +(9,39,"Album 39",282872); +(10,40,"Album 40",521496); +(11,41,"Album 41",98126); +(12,42,"Album 42",535113); +(13,43,"Album 43",957625); +(14,44,"Album 44",667630); +(15,45,"Album 45",236968); +(16,46,"Album 46",445647); +(17,47,"Album 47",446396); +(18,48,"Album 48",852859); +(19,49,"Album 49",404105); +(20,50,"Album 50",384439); +(21,51,"Album 51",440468); +(22,52,"Album 52",455384); +(23,53,"Album 53",210756); +(24,54,"Album 54",849113); +(25,55,"Album 55",63969); +(26,56,"Album 56",277122); +(27,57,"Album 57",350063); +(28,58,"Album 58",359473); +(29,59,"Album 59",209825); +(30,60,"Album 60",84543); diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Concerts.txt b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Concerts.txt new file mode 100644 index 000000000000..2e53d92ccafc --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Concerts.txt @@ -0,0 +1,100 @@ +(1,1,DATE '2003-06-19',TIMESTAMP '2003-06-19T12:30:05Z',TIMESTAMP '2003-06-19T18:57:15Z',[11,93,140,923]); +(2,18,DATE '2004-01-25',TIMESTAMP '2004-01-25T14:58:28Z',TIMESTAMP '2004-01-26T01:10:52Z',[18,51,101,812]); +(3,21,DATE '2005-03-15',TIMESTAMP '2005-03-15T18:14:50Z',TIMESTAMP '2005-03-16T02:21:28Z',[23,26,107,721]); +(4,16,DATE '2009-05-09',TIMESTAMP '2009-05-09T05:22:34Z',TIMESTAMP '2009-05-09T15:28:28Z',[18,70,150,297]); +(5,11,DATE '2001-01-07',TIMESTAMP '2001-01-07T18:37:33Z',TIMESTAMP '2001-01-07T21:22:17Z',[20,55,185,672]); +(6,25,DATE '2015-11-19',TIMESTAMP '2015-11-19T22:47:42Z',TIMESTAMP '2015-11-20T02:54:01Z',[12,73,150,833]); +(7,26,DATE '2012-10-06',TIMESTAMP '2012-10-06T10:58:43Z',TIMESTAMP '2012-10-06T15:35:40Z',[8,83,199,625]); +(8,8,DATE '2001-09-26',TIMESTAMP '2001-09-26T06:41:20Z',TIMESTAMP '2001-09-26T16:38:35Z',[19,87,192,912]); +(9,27,DATE '2016-11-24',TIMESTAMP '2016-11-24T20:00:48Z',TIMESTAMP '2016-11-24T23:03:07Z',[20,84,134,885]); +(10,30,DATE '2017-05-05',TIMESTAMP '2017-05-05T12:44:05Z',TIMESTAMP '2017-05-05T23:06:55Z',[17,44,177,997]); +(11,7,DATE '2018-06-07',TIMESTAMP '2018-06-07T07:03:11Z',TIMESTAMP '2018-06-07T08:21:41Z',[10,73,182,287]); +(12,22,DATE '2009-01-07',TIMESTAMP '2009-01-07T23:22:11Z',TIMESTAMP '2009-01-08T08:34:18Z',[22,59,150,983]); +(13,16,DATE '2013-06-28',TIMESTAMP '2013-06-28T14:59:25Z',TIMESTAMP '2013-06-28T22:32:11Z',[17,41,129,433]); +(14,11,DATE '2005-08-19',TIMESTAMP '2005-08-19T01:11:28Z',TIMESTAMP '2005-08-19T01:30:30Z',[18,49,110,590]); +(15,18,DATE '2001-11-26',TIMESTAMP '2001-11-26T15:55:31Z',TIMESTAMP '2001-11-26T20:52:13Z',[18,51,132,854]); +(16,26,DATE '2009-01-04',TIMESTAMP '2009-01-04T03:09:11Z',TIMESTAMP '2009-01-04T12:02:14Z',[5,37,146,344]); +(17,20,DATE '2012-09-28',TIMESTAMP '2012-09-28T00:45:00Z',TIMESTAMP '2012-09-28T02:10:39Z',[15,89,185,480]); +(18,24,DATE '2004-09-06',TIMESTAMP '2004-09-06T09:55:40Z',TIMESTAMP '2004-09-06T18:10:32Z',[23,51,113,244]); +(19,21,DATE '2010-11-18',TIMESTAMP '2010-11-18T09:59:17Z',TIMESTAMP '2010-11-18T17:13:12Z',[14,69,164,218]); +(20,29,DATE '2010-12-24',TIMESTAMP '2010-12-24T04:21:25Z',TIMESTAMP '2010-12-24T06:10:08Z',[20,34,166,573]); +(21,3,DATE '2000-05-14',TIMESTAMP '2000-05-14T13:49:08Z',TIMESTAMP '2000-05-14T14:39:25Z',[21,67,136,779]); +(22,18,DATE '2000-05-14',TIMESTAMP '2000-05-14T00:23:23Z',TIMESTAMP '2000-05-14T01:20:04Z',[21,91,111,749]); +(23,26,DATE '2015-05-04',TIMESTAMP '2015-05-04T10:39:46Z',TIMESTAMP '2015-05-04T19:21:45Z',[24,91,128,559]); +(24,16,DATE '2012-08-18',TIMESTAMP '2012-08-18T08:47:12Z',TIMESTAMP '2012-08-18T09:35:03Z',[19,44,136,281]); +(25,4,DATE '2000-03-16',TIMESTAMP '2000-03-16T10:15:15Z',TIMESTAMP '2000-03-16T12:29:53Z',[22,28,111,948]); +(26,4,DATE '2002-11-20',TIMESTAMP '2002-11-20T16:28:19Z',TIMESTAMP '2002-11-20T17:56:10Z',[7,70,141,517]); +(27,23,DATE '2000-08-09',TIMESTAMP '2000-08-09T04:30:51Z',TIMESTAMP '2000-08-09T15:27:15Z',[13,98,156,230]); +(28,16,DATE '2000-10-15',TIMESTAMP '2000-10-15T04:12:39Z',TIMESTAMP '2000-10-15T14:07:05Z',[8,39,160,455]); +(29,22,DATE '2003-03-25',TIMESTAMP '2003-03-25T17:21:56Z',TIMESTAMP '2003-03-25T19:18:25Z',[17,70,148,681]); +(30,15,DATE '2008-11-11',TIMESTAMP '2008-11-11T22:56:07Z',TIMESTAMP '2008-11-12T09:33:48Z',[24,47,175,901]); +(31,7,DATE '2018-05-22',TIMESTAMP '2018-05-22T20:54:59Z',TIMESTAMP '2018-05-23T02:52:28Z',[13,34,177,804]); +(32,30,DATE '2000-04-03',TIMESTAMP '2000-04-03T13:54:10Z',TIMESTAMP '2000-04-03T15:57:02Z',[16,48,137,249]); +(33,23,DATE '2003-12-24',TIMESTAMP '2003-12-24T22:22:00Z',TIMESTAMP '2003-12-25T06:09:40Z',[15,36,131,922]); +(34,12,DATE '2012-06-23',TIMESTAMP '2012-06-23T18:15:30Z',TIMESTAMP '2012-06-24T03:46:17Z',[25,31,160,564]); +(35,5,DATE '2017-12-15',TIMESTAMP '2017-12-15T09:43:38Z',TIMESTAMP '2017-12-15T17:18:28Z',[22,31,177,868]); +(36,20,DATE '2012-12-21',TIMESTAMP '2012-12-21T08:28:14Z',TIMESTAMP '2012-12-21T11:34:59Z',[25,62,143,437]); +(37,19,DATE '2014-07-07',TIMESTAMP '2014-07-07T22:01:35Z',TIMESTAMP '2014-07-08T04:39:37Z',[8,31,184,784]); +(38,15,DATE '2012-07-26',TIMESTAMP '2012-07-26T09:45:35Z',TIMESTAMP '2012-07-26T13:03:53Z',[19,79,140,908]); +(39,24,DATE '2014-03-19',TIMESTAMP '2014-03-19T07:52:25Z',TIMESTAMP '2014-03-19T11:47:01Z',[11,90,141,978]); +(40,4,DATE '2015-08-26',TIMESTAMP '2015-08-26T20:51:25Z',TIMESTAMP '2015-08-27T07:06:46Z',[15,94,195,510]); +(41,24,DATE '2016-04-11',TIMESTAMP '2016-04-11T08:59:07Z',TIMESTAMP '2016-04-11T13:23:30Z',[15,51,173,233]); +(42,18,DATE '2005-03-19',TIMESTAMP '2005-03-19T15:45:04Z',TIMESTAMP '2005-03-19T16:28:42Z',[19,31,188,546]); +(43,7,DATE '2001-01-04',TIMESTAMP '2001-01-04T11:02:16Z',TIMESTAMP '2001-01-04T11:32:21Z',[20,37,133,958]); +(44,5,DATE '2015-12-24',TIMESTAMP '2015-12-24T06:49:48Z',TIMESTAMP '2015-12-24T14:46:46Z',[12,61,175,233]); +(45,12,DATE '2011-08-24',TIMESTAMP '2011-08-24T03:45:46Z',TIMESTAMP '2011-08-24T06:13:10Z',[18,38,169,913]); +(46,16,DATE '2017-03-04',TIMESTAMP '2017-03-04T04:01:04Z',TIMESTAMP '2017-03-04T13:44:38Z',[21,79,119,839]); +(47,18,DATE '2009-05-19',TIMESTAMP '2009-05-19T23:10:52Z',TIMESTAMP '2009-05-20T04:02:01Z',[25,79,151,357]); +(48,22,DATE '2003-10-03',TIMESTAMP '2003-10-03T14:10:24Z',TIMESTAMP '2003-10-03T17:35:09Z',[18,60,140,450]); +(49,9,DATE '2003-03-07',TIMESTAMP '2003-03-07T22:09:59Z',TIMESTAMP '2003-03-08T08:28:29Z',[22,41,122,726]); +(50,9,DATE '2015-07-12',TIMESTAMP '2015-07-12T07:43:51Z',TIMESTAMP '2015-07-12T12:45:20Z',[18,67,126,474]); +(51,12,DATE '2014-11-05',TIMESTAMP '2014-11-05T19:03:00Z',TIMESTAMP '2014-11-06T05:27:07Z',[19,43,125,865]); +(52,6,DATE '2016-07-25',TIMESTAMP '2016-07-25T14:39:28Z',TIMESTAMP '2016-07-26T00:36:03Z',[6,74,192,344]); +(53,13,DATE '2005-08-02',TIMESTAMP '2005-08-02T16:06:47Z',TIMESTAMP '2005-08-02T17:13:41Z',[5,52,192,977]); +(54,18,DATE '2010-01-25',TIMESTAMP '2010-01-25T07:34:54Z',TIMESTAMP '2010-01-25T16:29:11Z',[24,85,181,304]); +(55,14,DATE '2012-05-20',TIMESTAMP '2012-05-20T13:15:12Z',TIMESTAMP '2012-05-20T17:40:09Z',[15,43,104,665]); +(56,3,DATE '2013-09-08',TIMESTAMP '2013-09-08T19:53:42Z',TIMESTAMP '2013-09-08T22:32:52Z',[14,81,129,354]); +(57,27,DATE '2003-07-18',TIMESTAMP '2003-07-18T23:11:24Z',TIMESTAMP '2003-07-19T03:29:46Z',[21,85,188,854]); +(58,27,DATE '2001-04-10',TIMESTAMP '2001-04-10T08:36:49Z',TIMESTAMP '2001-04-10T16:17:57Z',[17,86,161,438]); +(59,2,DATE '2002-07-02',TIMESTAMP '2002-07-02T17:32:20Z',TIMESTAMP '2002-07-03T01:59:33Z',[23,59,164,357]); +(60,28,DATE '2000-11-24',TIMESTAMP '2000-11-24T12:53:25Z',TIMESTAMP '2000-11-24T22:37:53Z',[22,47,161,739]); +(61,12,DATE '2017-07-04',TIMESTAMP '2017-07-04T21:02:01Z',TIMESTAMP '2017-07-05T03:57:29Z',[16,88,179,478]); +(62,3,DATE '2015-10-07',TIMESTAMP '2015-10-07T17:58:42Z',TIMESTAMP '2015-10-07T21:04:38Z',[21,44,155,381]); +(63,23,DATE '2005-05-03',TIMESTAMP '2005-05-03T15:08:10Z',TIMESTAMP '2005-05-03T20:58:30Z',[20,43,111,824]); +(64,24,DATE '2012-12-09',TIMESTAMP '2012-12-09T02:52:09Z',TIMESTAMP '2012-12-09T08:01:11Z',[18,87,106,997]); +(65,30,DATE '2004-03-01',TIMESTAMP '2004-03-01T07:09:06Z',TIMESTAMP '2004-03-01T07:49:32Z',[14,26,195,895]); +(66,24,DATE '2007-05-19',TIMESTAMP '2007-05-19T10:20:57Z',TIMESTAMP '2007-05-19T15:21:09Z',[18,54,179,238]); +(67,16,DATE '2016-01-06',TIMESTAMP '2016-01-06T21:32:20Z',TIMESTAMP '2016-01-07T02:31:32Z',[20,61,120,652]); +(68,2,DATE '2007-10-26',TIMESTAMP '2007-10-26T03:37:22Z',TIMESTAMP '2007-10-26T10:02:36Z',[11,65,151,537]); +(69,2,DATE '2018-08-11',TIMESTAMP '2018-08-11T01:33:38Z',TIMESTAMP '2018-08-11T07:39:21Z',[10,98,105,621]); +(70,23,DATE '2012-07-06',TIMESTAMP '2012-07-06T01:02:23Z',TIMESTAMP '2012-07-06T05:04:16Z',[14,44,172,953]); +(71,7,DATE '2006-01-24',TIMESTAMP '2006-01-24T15:32:10Z',TIMESTAMP '2006-01-24T17:40:43Z',[9,58,150,713]); +(72,8,DATE '2002-11-06',TIMESTAMP '2002-11-06T05:58:03Z',TIMESTAMP '2002-11-06T07:43:24Z',[25,36,193,213]); +(73,10,DATE '2003-11-24',TIMESTAMP '2003-11-24T17:39:10Z',TIMESTAMP '2003-11-25T03:17:36Z',[8,55,200,352]); +(74,16,DATE '2007-11-03',TIMESTAMP '2007-11-03T05:49:12Z',TIMESTAMP '2007-11-03T16:34:16Z',[21,50,114,820]); +(75,4,DATE '2009-05-06',TIMESTAMP '2009-05-06T18:52:07Z',TIMESTAMP '2009-05-06T21:10:02Z',[16,42,101,281]); +(76,1,DATE '2012-12-03',TIMESTAMP '2012-12-03T06:01:05Z',TIMESTAMP '2012-12-03T06:45:00Z',[24,60,140,292]); +(77,1,DATE '2016-11-26',TIMESTAMP '2016-11-26T01:19:27Z',TIMESTAMP '2016-11-26T07:20:17Z',[19,31,123,214]); +(78,9,DATE '2018-05-21',TIMESTAMP '2018-05-21T00:14:43Z',TIMESTAMP '2018-05-21T08:43:35Z',[7,28,115,634]); +(79,14,DATE '2013-11-20',TIMESTAMP '2013-11-20T08:54:47Z',TIMESTAMP '2013-11-20T10:44:54Z',[18,39,155,328]); +(80,17,DATE '2015-10-11',TIMESTAMP '2015-10-11T23:41:17Z',TIMESTAMP '2015-10-12T02:42:48Z',[16,94,102,894]); +(81,23,DATE '2011-08-07',TIMESTAMP '2011-08-07T19:33:01Z',TIMESTAMP '2011-08-07T21:51:53Z',[23,90,134,370]); +(82,7,DATE '2010-04-10',TIMESTAMP '2010-04-10T13:22:08Z',TIMESTAMP '2010-04-10T17:59:08Z',[18,68,121,303]); +(83,27,DATE '2001-07-08',TIMESTAMP '2001-07-08T20:19:54Z',TIMESTAMP '2001-07-08T22:46:15Z',[18,86,148,746]); +(84,6,DATE '2017-09-02',TIMESTAMP '2017-09-02T10:29:03Z',TIMESTAMP '2017-09-02T13:06:41Z',[12,85,138,471]); +(85,1,DATE '2013-11-02',TIMESTAMP '2013-11-02T04:01:03Z',TIMESTAMP '2013-11-02T14:08:47Z',[9,65,111,583]); +(86,22,DATE '2004-04-03',TIMESTAMP '2004-04-03T19:13:48Z',TIMESTAMP '2004-04-04T05:59:31Z',[19,72,105,908]); +(87,2,DATE '2012-02-26',TIMESTAMP '2012-02-26T22:52:21Z',TIMESTAMP '2012-02-27T02:55:24Z',[16,75,129,740]); +(88,9,DATE '2017-09-17',TIMESTAMP '2017-09-17T11:28:49Z',TIMESTAMP '2017-09-17T12:13:03Z',[24,77,182,755]); +(89,11,DATE '2011-03-28',TIMESTAMP '2011-03-28T13:05:23Z',TIMESTAMP '2011-03-28T16:32:29Z',[22,96,174,731]); +(90,21,DATE '2006-12-12',TIMESTAMP '2006-12-12T20:44:10Z',TIMESTAMP '2006-12-12T22:10:34Z',[15,68,166,616]); +(91,27,DATE '2010-08-18',TIMESTAMP '2010-08-18T05:49:35Z',TIMESTAMP '2010-08-18T12:58:36Z',[12,84,157,369]); +(92,2,DATE '2003-02-03',TIMESTAMP '2003-02-03T11:19:43Z',TIMESTAMP '2003-02-03T22:10:42Z',[25,59,140,939]); +(93,5,DATE '2016-01-04',TIMESTAMP '2016-01-04T08:10:26Z',TIMESTAMP '2016-01-04T13:08:30Z',[5,90,163,272]); +(94,3,DATE '2018-04-20',TIMESTAMP '2018-04-20T07:19:52Z',TIMESTAMP '2018-04-20T17:41:01Z',[5,59,109,854]); +(95,19,DATE '2016-10-09',TIMESTAMP '2016-10-09T17:02:59Z',TIMESTAMP '2016-10-09T17:37:27Z',[6,35,176,442]); +(96,9,DATE '2007-06-12',TIMESTAMP '2007-06-12T16:50:12Z',TIMESTAMP '2007-06-12T19:27:30Z',[7,49,169,729]); +(97,29,DATE '2012-11-25',TIMESTAMP '2012-11-25T20:40:30Z',TIMESTAMP '2012-11-25T21:29:50Z',[12,35,128,269]); +(98,11,DATE '2013-10-22',TIMESTAMP '2013-10-22T03:26:36Z',TIMESTAMP '2013-10-22T06:42:42Z',[14,49,148,726]); +(99,10,DATE '2006-05-10',TIMESTAMP '2006-05-10T05:49:43Z',TIMESTAMP '2006-05-10T07:12:18Z',[5,67,131,360]); +(100,18,DATE '2015-02-15',TIMESTAMP '2015-02-15T01:18:05Z',TIMESTAMP '2015-02-15T04:19:27Z',[11,38,127,909]); diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql new file mode 100644 index 000000000000..896b8b9cbf2e --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql @@ -0,0 +1,88 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +START BATCH DDL; + +CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + SingerInfo BYTES(MAX), + BirthDate DATE +) PRIMARY KEY(SingerId); + +CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName); + +CREATE TABLE Albums ( + SingerId INT64 NOT NULL, + AlbumId INT64 NOT NULL, + AlbumTitle STRING(MAX), + MarketingBudget INT64 +) PRIMARY KEY(SingerId, AlbumId), + INTERLEAVE IN PARENT Singers ON DELETE CASCADE; + +CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle); + +CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget); + +CREATE TABLE Songs ( + SingerId INT64 NOT NULL, + AlbumId INT64 NOT NULL, + TrackId INT64 NOT NULL, + SongName STRING(MAX), + Duration INT64, + SongGenre STRING(25) +) PRIMARY KEY(SingerId, AlbumId, TrackId), + INTERLEAVE IN PARENT Albums ON DELETE CASCADE; + +CREATE UNIQUE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums; + +CREATE INDEX SongsBySongName ON Songs(SongName); + +CREATE TABLE Concerts ( + VenueId INT64 NOT NULL, + SingerId INT64 NOT NULL, + ConcertDate DATE NOT NULL, + BeginTime TIMESTAMP, + EndTime TIMESTAMP, + TicketPrices ARRAY +) PRIMARY KEY(VenueId, SingerId, ConcertDate); + +CREATE TABLE TableWithAllColumnTypes ( + ColInt64 INT64 NOT NULL, + ColFloat64 FLOAT64 NOT NULL, + ColBool BOOL NOT NULL, + ColString STRING(100) NOT NULL, + ColStringMax STRING(MAX) NOT NULL, + ColBytes BYTES(100) NOT NULL, + ColBytesMax BYTES(MAX) NOT NULL, + ColDate DATE NOT NULL, + ColTimestamp TIMESTAMP NOT NULL, + ColCommitTS TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true), + + ColInt64Array ARRAY, + ColFloat64Array ARRAY, + ColBoolArray ARRAY, + ColStringArray ARRAY, + ColStringMaxArray ARRAY, + ColBytesArray ARRAY, + ColBytesMaxArray ARRAY, + ColDateArray ARRAY, + ColTimestampArray ARRAY +) PRIMARY KEY (ColInt64) +; + +RUN BATCH; \ No newline at end of file diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Singers.txt b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Singers.txt new file mode 100644 index 000000000000..939873de17e6 --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Singers.txt @@ -0,0 +1,30 @@ +(1,'First 1','A Last 1',FROM_BASE64('5KckBUgBLuj+nlmI0WXBEA0TCSeOK8x/B35kzIIHC01YrF8CNTjRT8hVQ4T0NkVGZjz96bF68aBu4QQ9VlZ/EhX22++vPADslt5YdqFzJjdxhlbGCufKIbrCVn1Po5u+j46SaV1TAHffIGfsAY0lhHJNmRS2P4p2/CGWJas4bzEo/Fn/JxuKF/et1LXgmlShOiE+LbnysvjbDt7GcbL7mA=='),DATE '1906-04-28'); +(2,'First 2','ALast 2',FROM_BASE64('1uLrsGLZS2BUfLGU0CLO9lgDau+TfX/XYK0RyEKvwgWdm3f0mbt4vbLziTn7iY/fM5OeGoeNZneQFWJoAY1XimD4aFDcQlIkkUxaXHFbOik4KNc/OiQMNaLghXtyaTP+UEaHX7o3w7iCp/wjzljEsnaYZxYTKY8Nm6JfKSwXvP1xHXi0KpaCdLf/V/8Vg102CNqqR4fgFwLy3/5QLxbGAg=='),DATE '1922-11-17'); +(3,'First 3','A Last 3',FROM_BASE64('Mc3i5IYbAWfrpZbCa8R2IXsK2DM0zW8mCx58tMClAPvIKktEIOh/HEl3l6qnJ8FPqp17E+PYZsplE9Hxu0LV9N1inR4TO+my3h9Vq72BA6hoSHmo2mxhRSF+iUL3TrC+MalcKPZuKnmI48RRfKoIrwP0Am1iqXWhhpOMo+zHDVL40FsbDIDW7zezTjyxPmwryF9I5vF+t1j8B5NKPA8Gnw=='),DATE '1935-11-08'); +(4,'First 4','A Last 4',FROM_BASE64('FyMiT7GA1pQzfrf/SnGN4iWMizOf+M59fVauKUqP84oGBSkI4F746K+grXinm3txsfPGu23J4OYtZt9FUxQssbaVykkhGBX9+nuiV+RYESLRj6uHT6mZH5g2BOR9L6cWRclks6GBFzIwjFu7JqeofmiJt/R1BwJMFH+07rDRPgi/9oS/DK6/ipC77dpomAuW48d9IbUNofd9/tc89mJbEg=='),DATE '1945-03-23'); +(5,'First 5','A Last 5',FROM_BASE64('BfpuifEdiau23UcEnnaONRxA9V0UH2uMhv3gZG/o0tnh6IR306luK4UL12RSbDVzGgpmDa7tLNC2pZzAlDMJmO4h5F73GzvSa8mVFrJrnqeNy9ECLM1sTIH1HYaF9jZXAYcSo14PK4+xygz1tsENs3jfKfWNuNBEi463x+fL8RcVxVMclSyOEBQaTnLD0pnzji99NkwMBQiwIHN5bl6XLA=='),DATE '1953-06-03'); +(6,'First 6','A Last 6',FROM_BASE64('Hdcj53Vc1yNAuCAP7H8YGadmbdOFGg1nfSpfVuiWWgx2OGR8KQIzTTHny8FsYnmyEBmJQZQMv1m1HU0EFmq5b4id0TmBUMfPzgWF5LFAJPgziAnbprYiKhwDaiRxrmL4Q0kVozeT1vniS3T6HioC20pjzmN8aF1vxzrLBr3IC9e8zHt9+Vla52lNoG/8atlWaSPx1agj5CyPncO7QTdPuw=='),DATE '1956-02-07'); +(7,'First 7','B Last 7',FROM_BASE64('FqOl3vAVSMU6NGINNZjVbYQRgmb95stb6CHfMYEec32ngI8XCS2687kGHfZ16innPuGau5Z/JSchkE8JYMaSITQ/7+B5eh40vZI1CKuLyXKfZ4BR8VkBVqxXyAsAShboxlt+kMHZEvWMY0iXcl9jCB3V+GNbPMHlCxz46CAnjp9ArnwwojRZgUDK9PonTr9N4GBEmO04DLip30LyvCpW/g=='),DATE '1969-05-26'); +(8,'First 8','B Last 8',FROM_BASE64('PQLBMSGGZXeSI7FLot4EcX3JfPTafiu5yeisMBQvuQmDW7kQC/mU9Oh+UhAbovDIx0dZGJ5dIhoAXZEzZPxGgBMWvbPNFmTB7+Q5Hd3/1uxL81XDZs6FlVCpGCKB0KER4WxtKbVqeQgltCeEvhYsTeLRNJdka33uq06lSZFyJXKX9bQyRLCZlGQRy2VHG1+sqjAX0FfcLf6RNEG64sDwOA=='),DATE '1978-11-08'); +(9,'First 9','B Last 9',FROM_BASE64('Nk2ZqJZSCFKKY+NMSq0WGVnNDS/BDHDEyb/bbJFxC/TqRPi+8DQ1csNlqvULW0pDEE6IygIRQR2lv5kT43E4tal4PKXx/z5LTeL9xiJ+qOHwLqAJrZK3V4aQFCNXT6t95lsxZLcjaP6fzNWlGwuN++iR7hpYJLI3WQSlaPL2GuHI9dLGS9ZUPR9KhDor72IURkOHU9Dt1eWfYouPsuVnrA=='),DATE '1987-07-04'); +(10,'First 10','B Last 10',FROM_BASE64('E0rzdg+IDhd1N9S/Nh11Yr6Za+xZlfCOQr0TrsxjFzRvO1ZnXjHGQPdWvT/LIJV+f7TXu0rYtk75fx7uPylxANNEYnLfD7v6UHB5Yful0TCweTFs9qH35BEd0jJl0ATb1ggUmsxXF0xZQpsRRnfycPbMY59w2APSX3hvgF2Xk7lvhHQaSbjnHOh4s78cqa2Atrjeds8KI/I4v+aVQIX9+Q=='),DATE '1993-07-06'); +(11,'First 11','C Last 11',FROM_BASE64('rO6MoGIcZJ+6zIPyMCt2td9ytNkSAn/LxWkrBKUGQs+Fk+Se43Ml7YsuRYhdcIeawAtySL35vZzb6Avl7bH/MyXrg4E0jdvjpEsi7KHiN4f0ky85purgyEg8tRASTi2zVsIM8c27DZenHOqRFl4KUaGRdQATOEoEIH3aHLVoACb0Y1m9JDTIDBcKST8nvTDzayQx1Ur4CO+ZqqG8ye99ww=='),DATE '1895-09-15'); +(12,'First 12','C Last 12',FROM_BASE64('ki4b0vB6EHp9qdm9lFrxplFPTnFCq9/BWwBLK1Jzz39K2q1rESpVXFIe2L2WzOKrunXo8e+p7+xlzBBKCwVIW6hQy0A+7kp7SwdZgWr2pXJqtSuo43fwfhf/A63zFaUYg3AkuNJNAtV/F3mOVudPeJ2xvfRfJ06uKY4MzsDhXAFW5Wsf1ypWMCke58U1VncvpuNOwzSb0El+hOreiQRX8g=='),DATE '1922-01-03'); +(13,'First 13','C Last 13',FROM_BASE64('KEx72v8CBibM16yet2U0Nsbt8KypF1ih18jLso5Q4AmFYUK7961GTYWj0YprWHxIxL/3qAXkm8jjtcRqEUmIXxW7kR0xC7sOcMYJsOSsy2m59YnDTlzDLlR1gynzNJVUhj+aKkUPMQfYV6Dw3UEx2Kik4NKDlGJQc9A0w3rfXjzRln8Ou3F+KYMuuoi/4jP4GEu1Pgyqy8jhQKiN0e9cjA=='),DATE '1930-08-03'); +(14,'First 14','C Last 14',FROM_BASE64('SdOTrssLh3vCqjtPNSqUvX5xrHs6/tpdlqgbp1jp9FseXhhJm+sq6FhgSMX+jm/grBUkUbGCNcWYthv3hdRMIapyZANENn/8CN0BxoVnvECGA9moThVIVghiSAiUNB+SyZg9XlmFRBaQcXpSWoZ1tIRTIuFRKpKaC2GYiOHVPLSQEUOBGc+sN4J0eCvM5aytanUGzn0o98yL73hbRXjwUw=='),DATE '1940-05-12'); +(15,'First 15','C Last 15',FROM_BASE64('NFgZNOzxoDSrAOPXtDIyUtetwm6eUN11YdjB7rIFfylx2SSTbhWZMuJoToE8xQz458BNaUJ8xPB+fJR2AQJL75eZdwJgSA7nnSiFcQgJxU7CEShlBT1ANNJvPujQ7cowRAo4joPfxoBSODuZcEc9WeXhJpEnlQtiGq7k+kzQ0oPgGaj0gLNwiC2zZwL5XCiet5qsRk4LSkUcX3OugpgeCg=='),DATE '1946-09-23'); +(16,'First 16','D Last 16',FROM_BASE64('mmXbRxEVEhiWeMGeuYOv6xGovovbq/qfevmWdMcGiqmCU1yzUrWKLvDhwzYZMbdscj7Tr5e4YyaXpIgpdMro3SApCyfhX5o/dsBlBNVmwLqg8DYbzAeApkaXeiStpAtKdQ8kZ1jezAFlhR/PioNsZjj1iAU4paFLG5F1i01spp3OOeJaD1mUTCSEO85rOAbQ8+B1N3vzz1Yc3E3mTQtxHg=='),DATE '1947-09-30'); +(17,'First 17','D Last 17',FROM_BASE64('zXIaISyrpPC/s0Yowmfdcbcavm6bGs95oBnWOHeTlXXk2n61Ug/GdG4gn5KxcXTfkqZAyzCBEnoaVcrwcp3HzEPUQeumXQn0dt2/oc5s0qfmGDo1+eOVy3tWMTdXv3vKmc4xXQ9bTMQE+MTtZDUknVCJ73zGUAMunFgzVnERLGBfOVaoLxcwC4HBrRtvtLlMboaCHirA1U5fF8xx81dK/g=='),DATE '1948-02-04'); +(18,'First 18','D Last 18',FROM_BASE64('mYZ5eW8+N/PFaDAmnIU77XX1jOZszdOXxblHbB0gKoJ6XOLYKcsmJKG8mjmUCQDYiG1b12xRQga6wprvLsciiyIwTCca6i4JL4RoVz+GqyDLmNSxHruz4xIB7XFIQ0q5SIeL7nob7llp7n+4+T9VYeoMDlFkG903WfjZNqsMRzpFYTT1C4ef+IlHOQSD5K3f/H/uWQ61PUebhSYe9hYQNg=='),DATE '1962-11-10'); +(19,'First 19','D Last 19',FROM_BASE64('/FqFHFjzF6yL/d3bKfSS9ZS1j8xkDlmF6gLpFf/MlC8idAt9ceLvr6oNEAKIdu0xqfLN9fKh9B7wQjAGUBKFLFlVzPIC2BBt7cCiiVVqgYwH3PIKiWL1LndLi1VRcNpy+gWLdgaFn+u4FxNotLDhdx9jUJOsDDPy9aBDSYmYOBajVUgN6jyfvG6egGnIhj+RNGxRkKfZ0isLOByT82v73w=='),DATE '1988-10-07'); +(20,'First 20','D Last 20',FROM_BASE64('3YII52xQjwk1RwhDPlbEKYWje92/04jIYhSJWa7LsLEt6qDxaFt1/1viQKAJWreCzgD0iC08CSJOQDLEmpuDPW5HZmWSnA0AuO46TGaYWtdQDFeJhgVzcldsAC7dMRid+SO1+sjvr/VfGCJP0XT3kWdE8mWNTdI74KrVm0CChj6XF7fLtjekbjZETrg7ySo8pmawVbTKrrZ5FIuNlkxI/Q=='),DATE '2000-02-29'); +(21,'First 21','D Last 21',FROM_BASE64('sKVHb3YTv4OPAB+77pjXln3omYqFy20LkBT/uP7PMSWlYaH+UpRdzOO52pDUh6BrMDjS3qgXU7irLoNA2NEma1QFzvVrLaa6yArnpZCyAEOw3OzpIQf2lJ7YqN8ZjwWEn8SztpMZBiJVXeZoYyYWnhkn9a+crIBOWMYI9ZfPUWk1xtvMX7I1QgHdSqPsLpT8iSnO42tjraGd5ulqkWrIRg=='),DATE '1886-08-09'); +(22,'First 22','E Last 22',FROM_BASE64('07GVEGBPEhQC8lELkxIGFhrQNspbl2NEGIrND5VXnUJFnuFctZaSpPovPHlYKtORcpGFsHTv3rSM6UUxTYFHzIUrxQJxNJ84KXjEXrlAN4tWkQOifh4icFc9FezQzQfsjf0KDjRatIFy8Q2jcSUfnhHbeZ1gpbsLIp8Ajioc7ptZG7Lnl1JyPmqKjQwQ+9WyE4uB0BGJTHI3xwzXQLm45A=='),DATE '1889-04-03'); +(23,'First 23','E Last 23',FROM_BASE64('tyGduCzcRQhWJXhDm5c9a8Mfpyyc1sKKk/OxSJFJ2numyNWuurKglMuDZSgdC9sH122eZdJU1uid7umiWYwhYYUC0JuYaYLNpYCnRuOL2FWVSN9jrJYX6AsNNpUDUfcKlJobFL/XJ+ulAr18Z/qtoWXDr4lx5TZAk05TTlFHJwRjIrybzrFYohhZZ20O4WtL3dryRKTgTgvVSElX0SZ8Tw=='),DATE '1892-01-21'); +(24,'First 24','E Last 24',FROM_BASE64('bXe6LecQB+BcWwzcE3b+JrH/20zrVIUXsH9AcBMduKoVIpCnrloUziiWbE1b2Te3/mD7ShKfD4RXSahJ7KgACA3CxS70yAa945NaqoX/aND7kGfFE6PEiS4pUrkJ10A1mRY2fP0J/Qn2tEyegtTF4b2BZuACQJy0qU8QyYrykaVK/+ExVI+MrvHA2LD062EDWPJrPgApCpPRMmtAV3KnTA=='),DATE '1898-02-21'); +(25,'First 25','Last 25',FROM_BASE64('82g7Ytc6/RBp/3vFxUG7JfAz9al82TRPlqBybWKBj/1pA26Pgv1UTxdDloQ24ovTmRZ3agPmaFEc/0ry820ozm8NmR340IwHRmO+jb2LQY4FGEMKFg7zDxAZpJXqITMZsFL1zO/EJ6VMnvZ90Udk2mywsnvv857PRCXJgx6vu4gn+oqUaRAQnSHq3pveu4/88FogqWoOotSzraD2RkW39Q=='),DATE '1911-12-15'); +(26,'First 26','Last 26',FROM_BASE64('KwbjBuHNQvzeWR2Ucf3v5dHAIO/b3/A0AlKxWI2qARDKuaXNuBooTCtdhIv5ZczOH5BbEKlaYkK3mr3GA5GClmwxsafbv3eE0LkV88T7KjfrKSkfatyTtcIWLIrw60B5hlMS5uxmj4X9nZfivj9boB4g3rqEdg/vgOsO9xdk/BKw6FMCuDO3PgDGEn89dOZmaB0PgadYNN3vqz8ZLgXWtg=='),DATE '1912-07-01'); +(27,'First 27','Last 27',FROM_BASE64('O3T43r6OjBwCWu925WlVnd6NLufFAken2Jk/QQBJOGQWsqc4dQsFhs/RSAC8iMZg32lfpfjMQPltRjmwqV7JleYRxL9e6co5WDj9cQk7AcL6wedgR5O/voPZIJ0aqkh5bZvijuxNIerbYhmYZEPOuzhgz9ayE7LgPkvO6WWNfhYuhnulnuDa3e2RsBNC7J1zuuf3DKHnL8SpaD0SMcZRuw=='),DATE '1939-05-17'); +(28,'First 28','Last 28',FROM_BASE64('xC71kYOpe6iZJd4DZnb11wBapa37lquOSW0JzuS15kW1xSG/Jxu0FXUIbFaBJ84hvFYQ3OSxr5HRxI0SBaFyUQhglUT3KTv/m8fEN/W+apBu4aUtlLcZPOTr1amaz30fu89J6pEoQOgmswSIr/0CtiaQ/ZHnuU2rZUXh7hTzBdygF30bAIq6yBGPpfb/MV66yagZtQO/q69sRmar70H/hg=='),DATE '1946-10-18'); +(29,'First 29','Last 29',FROM_BASE64('koHC6ZTUt89ksDORKlw5ep/zJCO0/LNo5A6yC5E8HEKOZpzX7xllDsIQuDmMQDn1HCHkpouKFmoTM24kWvfAs9B6yE7JccSFJbUU5s4Z/iLtYnnfKDzMEDDd/TyL6FxxS0McscfZ/TIc6ZFCArlJCbviqTSafPamrlD7tOJNxkCZae+dFIgnTCiTcwcjvkQeM5Ul6jDNoqIy5lrZdR6wJg=='),DATE '1956-12-23'); +(30,'First 30','Last 30',FROM_BASE64('WjdDzKHsiWCc0kXraf7NbebOU2TIv9KicHO6Og18iZpsxKH0am6wN7f1FwB1VSvZkvfJQgFkqjoqYEJ8qmgKB/YC9mbQAP14BjoJTq6fwDehF5leqSYT7NJarlhV7BX+hn4cCOBZ/gdGPCdK2aXZy8KJrnxh6RBGe0+84L3mEOaSZmZRvmXMcRjRozu17qV3xm6mo7BTq+/7tES3CAovMw=='),DATE '1988-05-29'); diff --git a/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Songs.txt b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Songs.txt new file mode 100644 index 000000000000..bda929b0fe5f --- /dev/null +++ b/google-cloud-clients/google-cloud-contrib/google-cloud-spanner-jdbc/src/test/resources/com/google/cloud/spanner/jdbc/it/Songs.txt @@ -0,0 +1,149 @@ +(12,42,1,"Song 12 42 1",387,'Unknown'); +(12,12,2,"Song 12 12 2",202,'Unknown'); +(29,59,3,"Song 29 59 3",160,'Unknown'); +(23,23,4,"Song 23 23 4",255,'Unknown'); +(24,54,5,"Song 24 54 5",436,'Unknown'); +(28,58,6,"Song 28 58 6",121,'Unknown'); +(27,27,7,"Song 27 27 7",319,'Unknown'); +(24,24,8,"Song 24 24 8",213,'Unknown'); +(19,49,9,"Song 19 49 9",280,'Unknown'); +(17,47,10,"Song 17 47 10",253,'Unknown'); +(6,6,11,"Song 6 6 11",321,'Unknown'); +(12,42,12,"Song 12 42 12 12 42 12",124,'Unknown'); +(25,25,13,"Song 25 25 13",449,'Unknown'); +(24,24,14,"Song 24 24 14",438,'Unknown'); +(5,5,15,"Song 5 5 15",378,'Unknown'); +(9,39,16,"Song 9 39 16",202,'Unknown'); +(20,50,17,"Song 20 50 17",452,'Unknown'); +(7,37,18,"Song 7 37 18",420,'Unknown'); +(8,8,19,"Song 8 8 19",318,'Unknown'); +(5,35,20,"Song 5 35 20",347,'Unknown'); +(3,3,21,"Song 3 3 21",377,'Unknown'); +(15,15,22,"Song 15 15 22",314,'Unknown'); +(19,49,23,"Song 19 49 23",199,'Unknown'); +(20,20,24,"Song 20 20 24",266,'Unknown'); +(15,45,25,"Song 15 45 25",433,'Unknown'); +(14,44,26,"Song 14 44 26",482,'Unknown'); +(19,19,27,"Song 19 19 27",345,'Unknown'); +(13,43,28,"Song 13 43 28",159,'Unknown'); +(18,48,29,"Song 18 48 29",350,'Unknown'); +(13,13,30,"Song 13 13 30",131,'Unknown'); +(9,9,31,"Song 9 9 31",183,'Unknown'); +(13,13,32,"Song 13 13 32",193,'Unknown'); +(24,24,33,"Song 24 24 33",378,'Unknown'); +(30,60,34,"Song 30 60 34",270,'Unknown'); +(13,43,35,"Song 13 43 35",375,'Unknown'); +(27,27,36,"Song 27 27 36",219,'Unknown'); +(20,50,37,"Song 20 50 37",314,'Unknown'); +(18,48,38,"Song 18 48 38",416,'Unknown'); +(21,51,39,"Song 21 51 39",330,'Unknown'); +(1,31,40,"Song 1 31 40",376,'Unknown'); +(5,5,41,"Song 5 5 41",398,'Unknown'); +(15,45,42,"Song 15 45 42",466,'Unknown'); +(24,24,43,"v 24 24 43",384,'Unknown'); +(19,19,44,"Song 19 19 44",472,'Unknown'); +(15,45,45,"Song 15 45 45",246,'Unknown'); +(3,33,46,"Song 3 33 46",412,'Unknown'); +(23,23,47,"Song 23 23 47",159,'Unknown'); +(30,60,48,"Song 30 60 48",290,'Unknown'); +(19,19,49,"Song 19 19 49",446,'Unknown'); +(16,16,50,"Song 16 16 50",485,'Unknown'); +(4,4,51,"Song 4 4 51",185,'Unknown'); +(8,38,52,"Song 8 38 52",349,'Unknown'); +(24,54,53,"Song 24 54 53",301,'Unknown'); +(5,35,54,"Song 5 35 54",206,'Unknown'); +(30,30,55,"Song 30 30 55",250,'Unknown'); +(12,42,56,"Song 12 42 56",146,'Unknown'); +(30,30,57,"Song 30 30 57",416,'Unknown'); +(26,56,58,"Song 26 56 58",244,'Unknown'); +(20,50,59,"Song 20 50 59",356,'Unknown'); +(7,7,60,"Song 7 7 60",234,'Unknown'); +(19,19,61,"Song 19 19 61",412,'Unknown'); +(13,43,62,"Song 13 43 62",161,'Unknown'); +(5,5,63,"Song 5 5 63",300,'Unknown'); +(1,31,64,"Song 1 31 64",307,'Unknown'); +(4,4,65,"Song 4 4 65",197,'Unknown'); +(24,54,66,"Song 24 54 66",180,'Unknown'); +(3,3,67,"Song 3 3 67",156,'Unknown'); +(14,44,68,"Song 14 44 68",184,'Unknown'); +(21,51,69,"Song 21 51 69",486,'Unknown'); +(19,49,70,"Song 19 49 70",212,'Unknown'); +(9,39,71,"Song 9 39 71",452,'Unknown'); +(23,53,72,"Song 23 53 72",425,'Unknown'); +(11,41,73,"Song 11 41 73",316,'Unknown'); +(8,8,74,"Song 8 8 74",395,'Unknown'); +(9,9,75,"Song 9 9 75",189,'Unknown'); +(2,2,76,"Song 2 2 76",354,'Unknown'); +(23,53,77,"Song 23 53 77",137,'Unknown'); +(15,15,78,"TSong 15 15 78",176,'Unknown'); +(30,60,79,"Song 30 60 79",224,'Unknown'); +(14,44,80,"Song 14 44 80",305,'Unknown'); +(27,27,81,"Song 27 27 81",432,'Unknown'); +(18,18,82,"Song 18 18 82",357,'Unknown'); +(10,10,83,"Song 10 10 83",187,'Unknown'); +(12,42,84,"Song 12 42 84",461,'Unknown'); +(8,8,85,"Song 8 8 85",434,'Unknown'); +(1,31,86,"Song 1 31 86",436,'Unknown'); +(11,41,87,"Song 11 41 87",469,'Unknown'); +(13,13,88,"Song 13 13 88",452,'Unknown'); +(4,34,89,"Song 4 34 89",309,'Unknown'); +(21,21,90,"Song 21 21 90",226,'Unknown'); +(6,36,91,"Song 6 36 91",257,'Unknown'); +(27,27,92,"Song 27 27 92",251,'Unknown'); +(9,39,93,"Song 9 39 93",325,'Unknown'); +(30,30,94,"Song 30 30 94",122,'Unknown'); +(29,59,95,"Song 29 59 95",207,'Unknown'); +(1,1,96,"Song 1 1 96",318,'Unknown'); +(4,4,97,"Song 4 4 97",353,'Unknown'); +(23,23,98,"Song 23 23 98",450,'Unknown'); +(12,12,99,"Song 12 12 99",323,'Unknown'); +(24,24,100,"Song 24 24 100",397,'Unknown'); +(27,27,101,"Song 27 27 101",296,'Unknown'); +(29,59,102,"Song 29 59 102",349,'Unknown'); +(17,47,103,"Song 17 47 103",438,'Unknown'); +(5,5,104,"Song 5 5 104",388,'Unknown'); +(26,56,105,"Song 26 56 105",425,'Unknown'); +(22,52,106,"Song 22 52 106",154,'Unknown'); +(23,23,107,"Song 23 23 107",213,'Unknown'); +(8,38,108,"Song 8 38 108",276,'Unknown'); +(9,39,109,"Song 9 39 109",417,'Unknown'); +(9,9,110,"Song 9 9 110",299,'Unknown'); +(22,52,111,"Song 22 52 111",476,'Unknown'); +(21,21,112,"Song 21 21 112",225,'Unknown'); +(23,23,113,"Song 23 23 113",303,'Unknown'); +(7,7,114,"Song 7 7 114",291,'Unknown'); +(8,38,115,"Song 8 38 115",276,'Unknown'); +(14,44,116,"Song 14 44 116",238,'Unknown'); +(27,57,117,"Song 27 57 117",188,'Unknown'); +(28,28,118,"Song 28 28 118",372,'Unknown'); +(15,15,119,"Song 15 15 119",258,'Unknown'); +(21,21,120,"Song 21 21 120",308,'Unknown'); +(29,59,121,"Song 29 59 121",319,'Unknown'); +(28,58,122,"Song 28 58 122",453,'Unknown'); +(7,7,123,"Song 7 7 123",198,'Unknown'); +(4,4,124,"Song 4 4 124",435,'Unknown'); +(27,27,125,"Song 27 27 125",475,'Unknown'); +(30,30,126,"Song 30 30 126",395,'Unknown'); +(21,51,127,"Song 21 51 127",454,'Unknown'); +(29,29,128,"Song 29 29 128",376,'Unknown'); +(27,57,129,"Song 27 57 129",396,'Unknown'); +(23,53,130,"Song 23 53 130",458,'Unknown'); +(6,36,131,"Song 6 36 131",289,'Unknown'); +(29,29,132,"Song 29 29 132",207,'Unknown'); +(25,55,133,"Song 25 55 133",280,'Unknown'); +(3,3,134,"Song 3 3 134",432,'Unknown'); +(5,35,135,"1 5 35 135",304,'Unknown'); +(3,3,136,"2 3 3 136",392,'Unknown'); +(12,12,137,"3 12 12 137",393,'Unknown'); +(13,13,138,"4 13 13 138",382,'Unknown'); +(18,48,139,"5 18 48 139",447,'Unknown'); +(17,17,140,"6 17 17 140",182,'Unknown'); +(23,23,141,"7 23 23 141",266,'Unknown'); +(21,51,142,"8 21 51 142",383,'Unknown'); +(3,3,143,"9 3 3 143",439,'Unknown'); +(25,25,144,"10 25 25 144",454,'Unknown'); +(12,12,145,"11 12 12 145",179,'Unknown'); +(19,19,146,"12 19 19 146",422,'Unknown'); +(24,54,147,"13 24 54 147",478,'Unknown'); +(8,38,148,"14 8 38 148",233,'Unknown'); +(6,6,149,"15 6 6 149",245,'Unknown');