diff --git a/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsCreateTableExample.java b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsCreateTableExample.java new file mode 100644 index 00000000000..7a9eed15c67 --- /dev/null +++ b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsCreateTableExample.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023 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.example.spanner.jdbc; + +import com.google.cloud.spanner.jdbc.CloudSpannerJdbcConnection; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.Arrays; + +class ProtoColumnsCreateTableExample { + + static void createTableWithProtoDataType() throws Exception { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + createTableWithProtoDataType(projectId, instanceId, databaseId); + } + + static void createTableWithProtoDataType(String projectId, String instanceId, String databaseId) + throws Exception { + String connectionUrl = + String.format( + "jdbc:cloudspanner://staging-wrenchworks.sandbox.googleapis.com/projects/%s/instances/%s/databases/%s", + projectId, instanceId, databaseId); + File file = new File("src/test/resources/descriptors.pb"); + InputStream in = new FileInputStream(file); + try (Connection connection = DriverManager.getConnection(connectionUrl)) { + CloudSpannerJdbcConnection spannerConnection = + connection.unwrap(CloudSpannerJdbcConnection.class); + spannerConnection.setProtoDescriptors(in); + spannerConnection.setAutoCommit(false); + Statement statement = spannerConnection.createStatement(); + statement.addBatch( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")"); + statement.addBatch( + "CREATE TABLE Singer (\n" + + " SingerId INT64 NOT NULL,\n" + + " FirstName STRING(1024),\n" + + " LastName STRING(1024),\n" + + " SingerInfo spanner.examples.music.SingerInfo,\n" + + " SingerGenre spanner.examples.music.Genre,\n" + + ") PRIMARY KEY (SingerId)\n"); + int[] val = statement.executeBatch(); + System.out.printf( + "Created table with Proto Message and Enum data type. DDL counts: %s", + Arrays.toString(val)); + } + } +} diff --git a/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsInsertDataExample.java b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsInsertDataExample.java new file mode 100644 index 00000000000..e9519084807 --- /dev/null +++ b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsInsertDataExample.java @@ -0,0 +1,101 @@ +/* + * Copyright 2023 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.example.spanner.jdbc; + +import com.example.spanner.jdbc.SingerProto.Genre; +import com.example.spanner.jdbc.SingerProto.SingerInfo; +import com.google.cloud.spanner.jdbc.ProtoEnumType; +import com.google.cloud.spanner.jdbc.ProtoMessageType; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +class ProtoColumnsInsertDataExample { + + // Class to contain Singer sample data. + static class Singer { + final long singerId; + final String firstName; + final String lastName; + final SingerInfo singerInfo; + final Genre singerGenre; + + Singer( + long singerId, + String firstName, + String lastName, + SingerInfo singerInfo, + Genre singerGenre) { + this.singerId = singerId; + this.firstName = firstName; + this.lastName = lastName; + this.singerInfo = singerInfo; + this.singerGenre = singerGenre; + } + } + + static final SingerInfo singerInfo = + SingerInfo.newBuilder() + .setSingerId(1) + .setNationality("Country1") + .setGenre(Genre.ROCK) + .build(); + static final List SINGERS = + Arrays.asList( + new Singer(1, "Marc", "Richards", singerInfo, Genre.ROCK), + new Singer(2, "Catalina", "Smith", null, null)); + + static void insertProtoColumnsData() throws SQLException { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + insertProtoColumnsData(projectId, instanceId, databaseId); + } + + static void insertProtoColumnsData(String projectId, String instanceId, String databaseId) + throws SQLException { + String connectionUrl = + String.format( + "jdbc:cloudspanner://staging-wrenchworks.sandbox.googleapis.com/projects/%s/instances/%s/databases/%s", + projectId, instanceId, databaseId); + try (Connection connection = DriverManager.getConnection(connectionUrl)) { + try (PreparedStatement ps = + connection.prepareStatement( + "INSERT INTO Singer" + + " (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (?, ?, ?, ?, ?)")) { + for (Singer singer : SINGERS) { + ps.setLong(1, singer.singerId); + ps.setString(2, singer.firstName); + ps.setString(3, singer.lastName); + // Tell the JDBC driver that we want to set a PROTO MESSAGE value + // by specifying the ProtoMessageType SQL type. + ps.setObject(4, singer.singerInfo, ProtoMessageType.INSTANCE); + // Tell the JDBC driver that we want to set a PROTO ENUM value + // by specifying the ProtoEnumType SQL type. + ps.setObject(5, singer.singerGenre, ProtoEnumType.INSTANCE); + ps.addBatch(); + } + int[] updateCounts = ps.executeBatch(); + System.out.printf("Insert counts: %s%n", Arrays.toString(updateCounts)); + } + } + } +} diff --git a/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsQueryDataExample.java b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsQueryDataExample.java new file mode 100644 index 00000000000..0b08f34ffd6 --- /dev/null +++ b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/ProtoColumnsQueryDataExample.java @@ -0,0 +1,55 @@ +/* + * Copyright 2023 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.example.spanner.jdbc; + +import com.example.spanner.jdbc.SingerProto.Genre; +import com.example.spanner.jdbc.SingerProto.SingerInfo; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +class ProtoColumnsQueryDataExample { + static void queryProtoColumnsData() throws SQLException { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project"; + String instanceId = "my-instance"; + String databaseId = "my-database"; + queryProtoColumnsData(projectId, instanceId, databaseId); + } + + static void queryProtoColumnsData(String projectId, String instanceId, String databaseId) + throws SQLException { + String connectionUrl = + String.format( + "jdbc:cloudspanner://staging-wrenchworks.sandbox.googleapis.com/projects/%s/instances/%s/databases/%s", + projectId, instanceId, databaseId); + try (Connection connection = DriverManager.getConnection(connectionUrl)) { + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery("SELECT SingerId, SingerInfo, SingerGenre FROM Singer"); + while (resultSet.next()) { + System.out.printf( + "SingerId: %s, SingerInfo: %s, SingerGenre: %s%n", + resultSet.getLong("SingerId"), + resultSet.getObject("SingerInfo", SingerInfo.class), + resultSet.getObject("SingerGenre", Genre.class)); + } + } + } +} diff --git a/spanner/jdbc/src/main/java/com/example/spanner/jdbc/SingerProto.java b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/SingerProto.java new file mode 100644 index 00000000000..0ce8d178942 --- /dev/null +++ b/spanner/jdbc/src/main/java/com/example/spanner/jdbc/SingerProto.java @@ -0,0 +1,1175 @@ +/* + * Copyright 2023 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. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: src/test/resources/com/google/cloud/spanner/singer.proto +package com.example.spanner.jdbc; + +public final class SingerProto { + private SingerProto() {} + + public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {} + + public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry); + } + /** Protobuf enum {@code spanner.examples.music.Genre} */ + public enum Genre implements com.google.protobuf.ProtocolMessageEnum { + /** POP = 0; */ + POP(0), + /** JAZZ = 1; */ + JAZZ(1), + /** FOLK = 2; */ + FOLK(2), + /** ROCK = 3; */ + ROCK(3), + ; + + /** POP = 0; */ + public static final int POP_VALUE = 0; + /** JAZZ = 1; */ + public static final int JAZZ_VALUE = 1; + /** FOLK = 2; */ + public static final int FOLK_VALUE = 2; + /** ROCK = 3; */ + public static final int ROCK_VALUE = 3; + + public final int getNumber() { + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @Deprecated + public static Genre valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static Genre forNumber(int value) { + switch (value) { + case 0: + return POP; + case 1: + return JAZZ; + case 2: + return FOLK; + case 3: + return ROCK; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Genre findValueByNumber(int number) { + return Genre.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + return getDescriptor().getValues().get(ordinal()); + } + + public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { + return getDescriptor(); + } + + public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { + return SingerProto.getDescriptor().getEnumTypes().get(0); + } + + private static final Genre[] VALUES = values(); + + public static Genre valueOf(com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new IllegalArgumentException("EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private Genre(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:spanner.examples.music.Genre) + } + + public interface SingerInfoOrBuilder + extends + // @@protoc_insertion_point(interface_extends:spanner.examples.music.SingerInfo) + com.google.protobuf.MessageOrBuilder { + + /** + * optional int64 singer_id = 1; + * + * @return Whether the singerId field is set. + */ + boolean hasSingerId(); + /** + * optional int64 singer_id = 1; + * + * @return The singerId. + */ + long getSingerId(); + + /** + * optional string birth_date = 2; + * + * @return Whether the birthDate field is set. + */ + boolean hasBirthDate(); + /** + * optional string birth_date = 2; + * + * @return The birthDate. + */ + String getBirthDate(); + /** + * optional string birth_date = 2; + * + * @return The bytes for birthDate. + */ + com.google.protobuf.ByteString getBirthDateBytes(); + + /** + * optional string nationality = 3; + * + * @return Whether the nationality field is set. + */ + boolean hasNationality(); + /** + * optional string nationality = 3; + * + * @return The nationality. + */ + String getNationality(); + /** + * optional string nationality = 3; + * + * @return The bytes for nationality. + */ + com.google.protobuf.ByteString getNationalityBytes(); + + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return Whether the genre field is set. + */ + boolean hasGenre(); + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return The genre. + */ + Genre getGenre(); + } + /** Protobuf type {@code spanner.examples.music.SingerInfo} */ + public static final class SingerInfo extends com.google.protobuf.GeneratedMessageV3 + implements + // @@protoc_insertion_point(message_implements:spanner.examples.music.SingerInfo) + SingerInfoOrBuilder { + private static final long serialVersionUID = 0L; + // Use SingerInfo.newBuilder() to construct. + private SingerInfo(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private SingerInfo() { + birthDate_ = ""; + nationality_ = ""; + genre_ = 0; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new SingerInfo(); + } + + @Override + public final com.google.protobuf.UnknownFieldSet getUnknownFields() { + return this.unknownFields; + } + + private SingerInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: + { + bitField0_ |= 0x00000001; + singerId_ = input.readInt64(); + break; + } + case 18: + { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000002; + birthDate_ = bs; + break; + } + case 26: + { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000004; + nationality_ = bs; + break; + } + case 32: + { + int rawValue = input.readEnum(); + @SuppressWarnings("deprecation") + Genre value = Genre.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(4, rawValue); + } else { + bitField0_ |= 0x00000008; + genre_ = rawValue; + } + break; + } + default: + { + if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return SingerProto.internal_static_spanner_examples_music_SingerInfo_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return SingerProto.internal_static_spanner_examples_music_SingerInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(SingerInfo.class, Builder.class); + } + + private int bitField0_; + public static final int SINGER_ID_FIELD_NUMBER = 1; + private long singerId_; + /** + * optional int64 singer_id = 1; + * + * @return Whether the singerId field is set. + */ + @Override + public boolean hasSingerId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional int64 singer_id = 1; + * + * @return The singerId. + */ + @Override + public long getSingerId() { + return singerId_; + } + + public static final int BIRTH_DATE_FIELD_NUMBER = 2; + private volatile Object birthDate_; + /** + * optional string birth_date = 2; + * + * @return Whether the birthDate field is set. + */ + @Override + public boolean hasBirthDate() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string birth_date = 2; + * + * @return The birthDate. + */ + @Override + public String getBirthDate() { + Object ref = birthDate_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + birthDate_ = s; + } + return s; + } + } + /** + * optional string birth_date = 2; + * + * @return The bytes for birthDate. + */ + @Override + public com.google.protobuf.ByteString getBirthDateBytes() { + Object ref = birthDate_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + birthDate_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int NATIONALITY_FIELD_NUMBER = 3; + private volatile Object nationality_; + /** + * optional string nationality = 3; + * + * @return Whether the nationality field is set. + */ + @Override + public boolean hasNationality() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * optional string nationality = 3; + * + * @return The nationality. + */ + @Override + public String getNationality() { + Object ref = nationality_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + nationality_ = s; + } + return s; + } + } + /** + * optional string nationality = 3; + * + * @return The bytes for nationality. + */ + @Override + public com.google.protobuf.ByteString getNationalityBytes() { + Object ref = nationality_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + nationality_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GENRE_FIELD_NUMBER = 4; + private int genre_; + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return Whether the genre field is set. + */ + @Override + public boolean hasGenre() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return The genre. + */ + @Override + public Genre getGenre() { + @SuppressWarnings("deprecation") + Genre result = Genre.valueOf(genre_); + return result == null ? Genre.POP : result; + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeInt64(1, singerId_); + } + if (((bitField0_ & 0x00000002) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, birthDate_); + } + if (((bitField0_ & 0x00000004) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, nationality_); + } + if (((bitField0_ & 0x00000008) != 0)) { + output.writeEnum(4, genre_); + } + unknownFields.writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeInt64Size(1, singerId_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, birthDate_); + } + if (((bitField0_ & 0x00000004) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, nationality_); + } + if (((bitField0_ & 0x00000008) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeEnumSize(4, genre_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof SingerInfo)) { + return super.equals(obj); + } + SingerInfo other = (SingerInfo) obj; + + if (hasSingerId() != other.hasSingerId()) return false; + if (hasSingerId()) { + if (getSingerId() != other.getSingerId()) return false; + } + if (hasBirthDate() != other.hasBirthDate()) return false; + if (hasBirthDate()) { + if (!getBirthDate().equals(other.getBirthDate())) return false; + } + if (hasNationality() != other.hasNationality()) return false; + if (hasNationality()) { + if (!getNationality().equals(other.getNationality())) return false; + } + if (hasGenre() != other.hasGenre()) return false; + if (hasGenre()) { + if (genre_ != other.genre_) return false; + } + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasSingerId()) { + hash = (37 * hash) + SINGER_ID_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong(getSingerId()); + } + if (hasBirthDate()) { + hash = (37 * hash) + BIRTH_DATE_FIELD_NUMBER; + hash = (53 * hash) + getBirthDate().hashCode(); + } + if (hasNationality()) { + hash = (37 * hash) + NATIONALITY_FIELD_NUMBER; + hash = (53 * hash) + getNationality().hashCode(); + } + if (hasGenre()) { + hash = (37 * hash) + GENRE_FIELD_NUMBER; + hash = (53 * hash) + genre_; + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static SingerInfo parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static SingerInfo parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static SingerInfo parseFrom(com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static SingerInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static SingerInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static SingerInfo parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static SingerInfo parseFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static SingerInfo parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static SingerInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); + } + + public static SingerInfo parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static SingerInfo parseFrom(com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static SingerInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(SingerInfo prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType(BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** Protobuf type {@code spanner.examples.music.SingerInfo} */ + public static final class Builder + extends com.google.protobuf.GeneratedMessageV3.Builder + implements + // @@protoc_insertion_point(builder_implements:spanner.examples.music.SingerInfo) + SingerInfoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return SingerProto.internal_static_spanner_examples_music_SingerInfo_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return SingerProto.internal_static_spanner_examples_music_SingerInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(SingerInfo.class, Builder.class); + } + + // Construct using com.google.cloud.spanner.SingerProto.SingerInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders) {} + } + + @Override + public Builder clear() { + super.clear(); + singerId_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + birthDate_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + nationality_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + genre_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return SingerProto.internal_static_spanner_examples_music_SingerInfo_descriptor; + } + + @Override + public SingerInfo getDefaultInstanceForType() { + return SingerInfo.getDefaultInstance(); + } + + @Override + public SingerInfo build() { + SingerInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public SingerInfo buildPartial() { + SingerInfo result = new SingerInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.singerId_ = singerId_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + to_bitField0_ |= 0x00000002; + } + result.birthDate_ = birthDate_; + if (((from_bitField0_ & 0x00000004) != 0)) { + to_bitField0_ |= 0x00000004; + } + result.nationality_ = nationality_; + if (((from_bitField0_ & 0x00000008) != 0)) { + to_bitField0_ |= 0x00000008; + } + result.genre_ = genre_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof SingerInfo) { + return mergeFrom((SingerInfo) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(SingerInfo other) { + if (other == SingerInfo.getDefaultInstance()) return this; + if (other.hasSingerId()) { + setSingerId(other.getSingerId()); + } + if (other.hasBirthDate()) { + bitField0_ |= 0x00000002; + birthDate_ = other.birthDate_; + onChanged(); + } + if (other.hasNationality()) { + bitField0_ |= 0x00000004; + nationality_ = other.nationality_; + onChanged(); + } + if (other.hasGenre()) { + setGenre(other.getGenre()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + SingerInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (SingerInfo) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private int bitField0_; + + private long singerId_; + /** + * optional int64 singer_id = 1; + * + * @return Whether the singerId field is set. + */ + @Override + public boolean hasSingerId() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional int64 singer_id = 1; + * + * @return The singerId. + */ + @Override + public long getSingerId() { + return singerId_; + } + /** + * optional int64 singer_id = 1; + * + * @param value The singerId to set. + * @return This builder for chaining. + */ + public Builder setSingerId(long value) { + bitField0_ |= 0x00000001; + singerId_ = value; + onChanged(); + return this; + } + /** + * optional int64 singer_id = 1; + * + * @return This builder for chaining. + */ + public Builder clearSingerId() { + bitField0_ = (bitField0_ & ~0x00000001); + singerId_ = 0L; + onChanged(); + return this; + } + + private Object birthDate_ = ""; + /** + * optional string birth_date = 2; + * + * @return Whether the birthDate field is set. + */ + public boolean hasBirthDate() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional string birth_date = 2; + * + * @return The birthDate. + */ + public String getBirthDate() { + Object ref = birthDate_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + birthDate_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * optional string birth_date = 2; + * + * @return The bytes for birthDate. + */ + public com.google.protobuf.ByteString getBirthDateBytes() { + Object ref = birthDate_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + birthDate_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string birth_date = 2; + * + * @param value The birthDate to set. + * @return This builder for chaining. + */ + public Builder setBirthDate(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + birthDate_ = value; + onChanged(); + return this; + } + /** + * optional string birth_date = 2; + * + * @return This builder for chaining. + */ + public Builder clearBirthDate() { + bitField0_ = (bitField0_ & ~0x00000002); + birthDate_ = getDefaultInstance().getBirthDate(); + onChanged(); + return this; + } + /** + * optional string birth_date = 2; + * + * @param value The bytes for birthDate to set. + * @return This builder for chaining. + */ + public Builder setBirthDateBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + birthDate_ = value; + onChanged(); + return this; + } + + private Object nationality_ = ""; + /** + * optional string nationality = 3; + * + * @return Whether the nationality field is set. + */ + public boolean hasNationality() { + return ((bitField0_ & 0x00000004) != 0); + } + /** + * optional string nationality = 3; + * + * @return The nationality. + */ + public String getNationality() { + Object ref = nationality_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + nationality_ = s; + } + return s; + } else { + return (String) ref; + } + } + /** + * optional string nationality = 3; + * + * @return The bytes for nationality. + */ + public com.google.protobuf.ByteString getNationalityBytes() { + Object ref = nationality_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + nationality_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string nationality = 3; + * + * @param value The nationality to set. + * @return This builder for chaining. + */ + public Builder setNationality(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + nationality_ = value; + onChanged(); + return this; + } + /** + * optional string nationality = 3; + * + * @return This builder for chaining. + */ + public Builder clearNationality() { + bitField0_ = (bitField0_ & ~0x00000004); + nationality_ = getDefaultInstance().getNationality(); + onChanged(); + return this; + } + /** + * optional string nationality = 3; + * + * @param value The bytes for nationality to set. + * @return This builder for chaining. + */ + public Builder setNationalityBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + nationality_ = value; + onChanged(); + return this; + } + + private int genre_ = 0; + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return Whether the genre field is set. + */ + @Override + public boolean hasGenre() { + return ((bitField0_ & 0x00000008) != 0); + } + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return The genre. + */ + @Override + public Genre getGenre() { + @SuppressWarnings("deprecation") + Genre result = Genre.valueOf(genre_); + return result == null ? Genre.POP : result; + } + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @param value The genre to set. + * @return This builder for chaining. + */ + public Builder setGenre(Genre value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + genre_ = value.getNumber(); + onChanged(); + return this; + } + /** + * optional .spanner.examples.music.Genre genre = 4; + * + * @return This builder for chaining. + */ + public Builder clearGenre() { + bitField0_ = (bitField0_ & ~0x00000008); + genre_ = 0; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:spanner.examples.music.SingerInfo) + } + + // @@protoc_insertion_point(class_scope:spanner.examples.music.SingerInfo) + private static final SingerInfo DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new SingerInfo(); + } + + public static SingerInfo getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @Deprecated + public static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public SingerInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new SingerInfo(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public SingerInfo getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_spanner_examples_music_SingerInfo_descriptor; + private static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_spanner_examples_music_SingerInfo_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor descriptor; + + static { + String[] descriptorData = { + "\n\014singer.proto\022\026spanner.examples.music\"v" + + "\n\nSingerInfo\022\021\n\tsinger_id\030\001 \001(\003\022\022\n\nbirth" + + "_date\030\002 \001(\t\022\023\n\013nationality\030\003 \001(\t\022,\n\005genr" + + "e\030\004 \001(\0162\035.spanner.examples.music.Genre*." + + "\n\005Genre\022\007\n\003POP\020\000\022\010\n\004JAZZ\020\001\022\010\n\004FOLK\020\002\022\010\n\004" + + "ROCK\020\003B)\n\030com.google.cloud.spannerB\013Sing" + + "erProtoP\000" + }; + descriptor = + com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( + descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}); + internal_static_spanner_examples_music_SingerInfo_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_spanner_examples_music_SingerInfo_fieldAccessorTable = + new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_spanner_examples_music_SingerInfo_descriptor, + new String[] { + "SingerId", "BirthDate", "Nationality", "Genre", + }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/spanner/jdbc/src/test/java/com/example/spanner/jdbc/JdbcExamplesIT.java b/spanner/jdbc/src/test/java/com/example/spanner/jdbc/JdbcExamplesIT.java index 366547b491a..ae8a9665372 100644 --- a/spanner/jdbc/src/test/java/com/example/spanner/jdbc/JdbcExamplesIT.java +++ b/spanner/jdbc/src/test/java/com/example/spanner/jdbc/JdbcExamplesIT.java @@ -18,6 +18,8 @@ import static com.google.common.truth.Truth.assertThat; +import com.example.spanner.jdbc.SingerProto.Genre; +import com.example.spanner.jdbc.SingerProto.SingerInfo; import com.google.cloud.ServiceOptions; import com.google.cloud.spanner.DatabaseAdminClient; import com.google.cloud.spanner.DatabaseId; @@ -52,7 +54,8 @@ @SuppressWarnings("checkstyle:AbbreviationAsWordInName") public class JdbcExamplesIT { // The instance needs to exist for tests to pass. - private static String instanceId = System.getProperty("spanner.test.instance"); + private static String instanceId = + System.getProperty("spanner.test.instance", "harsha-test-gcloud"); private static String databaseId = formatForTest(System.getProperty("spanner.sample.database", "mysample")); private static DatabaseId dbId; @@ -78,7 +81,11 @@ private String runExample(JdbcRunnable example) throws SQLException { @BeforeClass public static void createTestDatabase() throws Exception { - SpannerOptions options = SpannerOptions.newBuilder().build(); + SpannerOptions options = + SpannerOptions.newBuilder() + .setProjectId("span-cloud-testing") + .setHost("https://staging-wrenchworks.sandbox.googleapis.com") + .build(); Spanner spanner = options.getService(); dbClient = spanner.getDatabaseAdminClient(); if (instanceId == null) { @@ -447,6 +454,36 @@ public void insertAndQueryJsonData_shouldReturnData() throws SQLException { assertThat(out).contains("VenueId: 19"); } + @Test + public void insertAndQueryProtoColumnsData_shouldReturnData() throws SQLException { + String out = + runExample( + () -> + ProtoColumnsCreateTableExample.createTableWithProtoDataType( + ServiceOptions.getDefaultProjectId(), instanceId, databaseId)); + assertThat(out) + .contains("Created table with Proto Message and Enum data type. DDL counts: [-2, -2]"); + out = + runExample( + () -> + ProtoColumnsInsertDataExample.insertProtoColumnsData( + ServiceOptions.getDefaultProjectId(), instanceId, databaseId)); + assertThat(out).contains("Insert counts: [1, 1]"); + out = + runExample( + () -> + ProtoColumnsQueryDataExample.queryProtoColumnsData( + ServiceOptions.getDefaultProjectId(), instanceId, databaseId)); + SingerInfo singerInfo = + SingerInfo.newBuilder() + .setSingerId(1) + .setNationality("Country1") + .setGenre(Genre.ROCK) + .build(); + assertThat(out).contains("SingerId: 1, SingerInfo: " + singerInfo + ", SingerGenre: ROCK"); + assertThat(out).contains("SingerId: 2, SingerInfo: null, SingerGenre: null"); + } + static String formatForTest(String name) { return name + "-" + UUID.randomUUID().toString().substring(0, 20); } diff --git a/spanner/jdbc/src/test/resources/descriptors.pb b/spanner/jdbc/src/test/resources/descriptors.pb new file mode 100644 index 00000000000..3ebb79420b3 Binary files /dev/null and b/spanner/jdbc/src/test/resources/descriptors.pb differ