Skip to content

Commit 357f092

Browse files
committed
docs: add sample for PROTO columns
Adds a sample for using PROTO columns with the JDBC driver. Fixes #1916
1 parent 4744c11 commit 357f092

File tree

8 files changed

+1335
-2
lines changed

8 files changed

+1335
-2
lines changed

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,19 @@ activate the `shade` profile like this:
155155
mvn package -Pshade
156156
```
157157

158-
159-
158+
## Samples
159+
160+
See the [samples](/samples) directory for various examples for using the Spanner JDBC driver.
161+
162+
- [snippets](/samples/snippets): Contains small code snippets for commonly used JDBC and Spanner
163+
features. Refer to these snippets for examples on how to execute DDL and DML batches, use various
164+
data types with the JDBC driver, execute various types of transactions (read/write, read-only,
165+
Partitioned DML), use request and transaction tags, etc.
166+
- [spring-data-jdbc](/samples/spring-data-jdbc): Contains a sample application that uses Spring Data
167+
JDBC in combination with a Spanner PostgreSQL database.
168+
- [spring-data-mybatis](/samples/spring-data-mybatis): Contains a sample application that uses
169+
Spring Data MyBatis in combination with a Spanner PostgreSQL database.
170+
- [quickperf](/samples/quickperf): Contains a simple benchmarking application.
160171

161172

162173
## Troubleshooting

samples/snapshot/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<groupId>com.google.cloud.samples</groupId>
1616
<artifactId>shared-configuration</artifactId>
1717
<version>1.2.2</version>
18+
<relativePath/>
1819
</parent>
1920

2021
<properties>

samples/snippets/src/main/java/com/example/spanner/jdbc/JdbcSample.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.example.spanner.jdbc;
1818

19+
import com.example.spanner.jdbc.SingerProto.Genre;
20+
import com.example.spanner.jdbc.SingerProto.SingerInfo;
1921
import com.google.api.gax.core.NoCredentialsProvider;
2022
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
2123
import com.google.cloud.spanner.DatabaseId;
@@ -29,13 +31,19 @@
2931
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
3032
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminSettings;
3133
import com.google.cloud.spanner.jdbc.CloudSpannerJdbcConnection;
34+
import com.google.cloud.spanner.jdbc.CloudSpannerJdbcPreparedStatement;
35+
import com.google.cloud.spanner.jdbc.ProtoEnumType;
36+
import com.google.cloud.spanner.jdbc.ProtoMessageType;
3237
import com.google.common.base.Strings;
3338
import com.google.common.collect.ImmutableList;
3439
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
3540
import com.google.spanner.admin.database.v1.DatabaseDialect;
3641
import com.google.spanner.admin.instance.v1.InstanceName;
3742
import com.google.spanner.v1.DatabaseName;
3843
import io.grpc.ManagedChannelBuilder;
44+
import java.io.IOException;
45+
import java.io.InputStream;
46+
import java.net.URL;
3947
import java.sql.Connection;
4048
import java.sql.DriverManager;
4149
import java.sql.PreparedStatement;
@@ -1576,6 +1584,97 @@ static void arrayOfStructAsQueryParameter(
15761584
}
15771585
}
15781586

1587+
static void protoColumns(
1588+
final String project,
1589+
final String instance,
1590+
final String database,
1591+
final Properties properties) throws SQLException, IOException {
1592+
try (Connection connection =
1593+
DriverManager.getConnection(
1594+
String.format(
1595+
"jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s",
1596+
project, instance, database),
1597+
properties)) {
1598+
// Create a PROTO BUNDLE and a table.
1599+
try (Statement statement = connection.createStatement();
1600+
InputStream protoDescriptors = JdbcSample.class.getClassLoader()
1601+
.getResourceAsStream("com/example/spanner/jdbc/descriptors.pb")) {
1602+
if (protoDescriptors == null) {
1603+
throw new IllegalArgumentException("proto descriptors not found");
1604+
}
1605+
1606+
// Unwrap the CloudSpannerJdbcConnection interface to set the proto
1607+
// descriptors that should be used for the next DDL statements.
1608+
connection
1609+
.unwrap(CloudSpannerJdbcConnection.class)
1610+
.setProtoDescriptors(protoDescriptors);
1611+
// Execute the DDL statements as one batch.
1612+
// This will reduce execution time compared to executing each statement
1613+
// sequentially.
1614+
statement.addBatch("CREATE PROTO BUNDLE (\n"
1615+
+ "examples.spanner.music.SingerInfo,\n"
1616+
+ "examples.spanner.music.Genre,\n"
1617+
+ ")");
1618+
statement.addBatch("CREATE TABLE SingersWithProto (\n"
1619+
+ " SingerId INT64 NOT NULL,\n"
1620+
+ " SingerInfo examples.spanner.music.SingerInfo,\n"
1621+
+ " SingerGenre examples.spanner.music.Genre,\n"
1622+
+ ") PRIMARY KEY (SingerId)");
1623+
statement.executeBatch();
1624+
}
1625+
1626+
// Insert a couple of rows using a prepared statement.
1627+
// Use the ProtoMessageType and ProtoEnumType vendor type numbers
1628+
// to indicate that the values should be seen as respectively proto
1629+
// messages and proto enums.
1630+
try (PreparedStatement statement = connection.prepareStatement(
1631+
"INSERT INTO SingersWithProto "
1632+
+ "(SingerId, SingerInfo, SingerGenre) "
1633+
+ "VALUES (?, ?, ?)")) {
1634+
statement.setLong(1, 1L);
1635+
statement.setObject(2,
1636+
SingerInfo.newBuilder()
1637+
.setGenre(Genre.ROCK)
1638+
.setBirthDate("1998-07-04")
1639+
.setSingerId(1L)
1640+
.setNationality("ES")
1641+
.build(), ProtoMessageType.VENDOR_TYPE_NUMBER);
1642+
statement.setObject(3, Genre.ROCK, ProtoEnumType.VENDOR_TYPE_NUMBER);
1643+
statement.addBatch();
1644+
1645+
statement.setLong(1, 2L);
1646+
statement.setObject(2,
1647+
SingerInfo.newBuilder()
1648+
.setGenre(Genre.POP)
1649+
.setBirthDate("2001-12-03")
1650+
.setSingerId(2L)
1651+
.setNationality("FO")
1652+
.build(), ProtoMessageType.VENDOR_TYPE_NUMBER);
1653+
statement.setObject(3, Genre.POP, ProtoEnumType.VENDOR_TYPE_NUMBER);
1654+
statement.addBatch();
1655+
1656+
int[] updateCounts = statement.executeBatch();
1657+
System.out.printf("Inserted %d singers\n",
1658+
Arrays.stream(updateCounts).sum());
1659+
}
1660+
1661+
// Read the inserted rows.
1662+
try (ResultSet resultSet = connection.createStatement()
1663+
.executeQuery("SELECT * FROM SingersWithProto")) {
1664+
while (resultSet.next()) {
1665+
long singerId = resultSet.getLong(1);
1666+
// Proto messages and proto enums can be retrieved with the
1667+
// ResultSet#getObject(int, Class) method.
1668+
// The Spanner JDBC driver automatically deserializes
1669+
// and converts the column to the Java class representation.
1670+
SingerInfo info = resultSet.getObject(2, SingerInfo.class);
1671+
Genre genre = resultSet.getObject(3, Genre.class);
1672+
System.out.printf("%d:\n%s\n%s\n", singerId, info, genre);
1673+
}
1674+
}
1675+
}
1676+
}
1677+
15791678
/** The expected number of command line arguments. */
15801679
private static final int NUM_EXPECTED_ARGS = 3;
15811680

@@ -1761,6 +1860,13 @@ static boolean runGoogleSQLSample(
17611860
database.getDatabase(),
17621861
createProperties());
17631862
return true;
1863+
case "protocolumns":
1864+
protoColumns(
1865+
database.getInstanceId().getProject(),
1866+
database.getInstanceId().getInstance(),
1867+
database.getDatabase(),
1868+
createProperties());
1869+
return true;
17641870
default:
17651871
return false;
17661872
}

0 commit comments

Comments
 (0)