diff --git a/.github/workflows/integration-tests-on-emulator.yml b/.github/workflows/integration-tests-on-emulator.yml index 38a57e1c..acecd5fa 100644 --- a/.github/workflows/integration-tests-on-emulator.yml +++ b/.github/workflows/integration-tests-on-emulator.yml @@ -2,9 +2,13 @@ on: push: branches: [ main ] pull_request: + name: Integration tests on emulator + jobs: - test: + # This is the original job, renamed for clarity + test-go: + name: Go Integration Tests runs-on: ubuntu-latest services: emulator: @@ -18,11 +22,37 @@ jobs: with: go-version: 1.25.x - name: Checkout code - uses: actions/checkout@v5 - - name: Run integration tests on emulator + uses: actions/checkout@v4 + - name: Run Go integration tests on emulator run: go test -race env: JOB_TYPE: test SPANNER_EMULATOR_HOST: localhost:9010 SPANNER_TEST_PROJECT: emulator-test-project SPANNER_TEST_INSTANCE: test-instance + + test-ruby: + name: Ruby Integration Tests + runs-on: ubuntu-latest + services: + emulator: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + - 9020:9020 + steps: + - name: Checkout code + uses: actions/checkout@v5 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3.1' + working-directory: spannerlib/wrappers/spannerlib-ruby + bundler-cache: true + - name: Compile and Run Ruby Integration Tests + working-directory: spannerlib/wrappers/spannerlib-ruby + env: + SPANNER_EMULATOR_HOST: localhost:9010 + run: | + bundle exec rake compile + bundle exec rspec spec/integration/ diff --git a/.github/workflows/spanner-lib-tests.yml b/.github/workflows/spanner-lib-tests.yml index b6df5ccd..915d9030 100644 --- a/.github/workflows/spanner-lib-tests.yml +++ b/.github/workflows/spanner-lib-tests.yml @@ -15,11 +15,11 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Run unit tests working-directory: spannerlib run: go test ./... -race -short @@ -32,17 +32,17 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: 21 - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check Java formatting run: mvn com.spotify.fmt:fmt-maven-plugin:check working-directory: spannerlib/wrappers/spannerlib-java - name: Install Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-version }} - name: Build shared library @@ -97,6 +97,8 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v4 + with: + submodules: 'true' - name: Build shared library working-directory: spannerlib/shared run: go build -o spannerlib.so -buildmode=c-shared shared_lib.go @@ -124,6 +126,34 @@ jobs: fi working-directory: spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-native shell: bash + - name: Build gRPC server + working-directory: spannerlib/grpc-server + run: | + go build -o grpc_server server.go + chmod +x grpc_server + - name: Copy gRPC server to .NET wrapper + working-directory: spannerlib + run: | + mkdir -p wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/binaries/any + if [ "$RUNNER_OS" == "Windows" ]; then + cp grpc-server/grpc_server wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/binaries/any/grpc_server.exe + else + cp grpc-server/grpc_server wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/binaries/any/grpc_server + fi + shell: bash + - name: Build .NET gRPC server package + run: dotnet pack + working-directory: spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server + shell: bash + - name: Add .NET package source + run: | + if [ "$RUNNER_OS" == "Windows" ]; then + dotnet nuget add source ${GITHUB_WORKSPACE}"\spannerlib\wrappers\spannerlib-dotnet\spannerlib-dotnet-grpc-server\bin\Release" --name local-grpc-server + else + dotnet nuget add source "$PWD"/bin/Release --name local-grpc-server + fi + working-directory: spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server + shell: bash - name: Restore dependencies run: dotnet restore working-directory: spannerlib/wrappers/spannerlib-dotnet diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4ce109ae..de44c40d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.18.0" + ".": "1.19.0" } \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 021fe111..abd0a1eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,31 @@ # Changelog +## [1.19.0](https://github.com/googleapis/go-sql-spanner/compare/v1.18.1...v1.19.0) (2025-10-07) + + +### Features + +* Add authority param support to DSN ([#546](https://github.com/googleapis/go-sql-spanner/issues/546)) ([002d386](https://github.com/googleapis/go-sql-spanner/commit/002d386b88d031ad4c8e8cb98153678ad5a74cba)) +* **ruby:** Add Ruby FFI wrapper for spannerlib ([#545](https://github.com/googleapis/go-sql-spanner/issues/545)) ([bb87d96](https://github.com/googleapis/go-sql-spanner/commit/bb87d9605f38cb875ec83a61a216d8697e60f490)) + + +### Bug Fixes + +* Update all dependencies ([#542](https://github.com/googleapis/go-sql-spanner/issues/542)) ([fba2986](https://github.com/googleapis/go-sql-spanner/commit/fba2986be9416ba761285645644d9a5a8eb7180b)) +* Update dependency net.java.dev.jna:jna to v5.18.1 ([#544](https://github.com/googleapis/go-sql-spanner/issues/544)) ([98f2429](https://github.com/googleapis/go-sql-spanner/commit/98f24298fe58ef31ddf8a35923912e998e4d133b)) +* Update module github.com/googleapis/go-sql-spanner to v1.18.1 ([#540](https://github.com/googleapis/go-sql-spanner/issues/540)) ([1eca441](https://github.com/googleapis/go-sql-spanner/commit/1eca4414dfddef2c5e9e3642712317c3929738be)) + +## [1.18.1](https://github.com/googleapis/go-sql-spanner/compare/v1.18.0...v1.18.1) (2025-09-23) + + +### Bug Fixes + +* Do not return update count for queries ([#524](https://github.com/googleapis/go-sql-spanner/issues/524)) ([4403e52](https://github.com/googleapis/go-sql-spanner/commit/4403e5287515c83fb889f9e7f8a107f9cfdb1ea8)) +* Update all dependencies ([#536](https://github.com/googleapis/go-sql-spanner/issues/536)) ([13bda8d](https://github.com/googleapis/go-sql-spanner/commit/13bda8dae03e8af663450e21a888808521857c81)) +* Update dependency net.java.dev.jna:jna to v5.18.0 ([#538](https://github.com/googleapis/go-sql-spanner/issues/538)) ([61cc7e8](https://github.com/googleapis/go-sql-spanner/commit/61cc7e81908e9b5eef42ce2d1e6dec2ec7c044e9)) +* Update module github.com/googleapis/go-sql-spanner to v1.18.0 ([#528](https://github.com/googleapis/go-sql-spanner/issues/528)) ([f5100ce](https://github.com/googleapis/go-sql-spanner/commit/f5100cec9d99099b3a538e45688f27f0c3dd0376)) +* Update module github.com/testcontainers/testcontainers-go to v0.39.0 ([#535](https://github.com/googleapis/go-sql-spanner/issues/535)) ([c3a8109](https://github.com/googleapis/go-sql-spanner/commit/c3a8109084ee4a876ae5a57aec015d330e25b381)) + ## [1.18.0](https://github.com/googleapis/go-sql-spanner/compare/v1.17.0...v1.18.0) (2025-09-12) diff --git a/benchmarks/go.mod b/benchmarks/go.mod index aafed8da..78dcf556 100644 --- a/benchmarks/go.mod +++ b/benchmarks/go.mod @@ -7,20 +7,20 @@ toolchain go1.25.1 replace github.com/googleapis/go-sql-spanner => ../ require ( - cloud.google.com/go v0.122.0 - cloud.google.com/go/spanner v1.85.1 + cloud.google.com/go v0.123.0 + cloud.google.com/go/spanner v1.86.0 github.com/google/uuid v1.6.0 - github.com/googleapis/go-sql-spanner v1.18.0 - google.golang.org/api v0.249.0 + github.com/googleapis/go-sql-spanner v1.18.1 + google.golang.org/api v0.251.0 google.golang.org/grpc v1.75.1 - google.golang.org/protobuf v1.36.9 + google.golang.org/protobuf v1.36.10 ) require ( cel.dev/expr v0.24.0 // indirect cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.8.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect @@ -52,14 +52,14 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.12.0 // indirect + golang.org/x/crypto v0.42.0 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/oauth2 v0.31.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.13.0 // indirect google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect ) diff --git a/benchmarks/go.sum b/benchmarks/go.sum index facf0032..37cdcdc0 100644 --- a/benchmarks/go.sum +++ b/benchmarks/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= -cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= -cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -526,8 +526,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.85.1 h1:cJx1ZD//C2QIfFQl8hSTn4twL8amAXtnayyflRIjj40= -cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= +cloud.google.com/go/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -955,8 +955,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1071,8 +1071,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1102,8 +1102,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1120,8 +1120,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1199,8 +1199,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1225,16 +1225,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1371,8 +1371,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w= -google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ= +google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= +google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1516,8 +1516,8 @@ google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyT google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1579,8 +1579,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/conn.go b/conn.go index 31dc2c41..d35b238d 100644 --- a/conn.go +++ b/conn.go @@ -275,14 +275,9 @@ type conn struct { // tempExecOptions can be set by passing it in as an argument to ExecContext or QueryContext // and are applied only to that statement. tempExecOptions *ExecOptions - // tempTransactionOptions are temporarily set right before a read/write transaction is started. - tempTransactionOptions *ReadWriteTransactionOptions - // tempReadOnlyTransactionOptions are temporarily set right before a read-only - // transaction is started on a Spanner connection. - tempReadOnlyTransactionOptions *ReadOnlyTransactionOptions - // tempBatchReadOnlyTransactionOptions are temporarily set right before a - // batch read-only transaction is started on a Spanner connection. - tempBatchReadOnlyTransactionOptions *BatchReadOnlyTransactionOptions + // tempTransactionCloseFunc is set right before a transaction is started, and is set as the + // close function for that transaction. + tempTransactionCloseFunc func() } func (c *conn) UnderlyingClient() (*spanner.Client, error) { @@ -332,13 +327,18 @@ func (c *conn) showConnectionVariable(identifier parser.Identifier) (any, bool, return c.state.GetValue(extension, name) } -func (c *conn) setConnectionVariable(identifier parser.Identifier, value string, local bool) error { +func (c *conn) setConnectionVariable(identifier parser.Identifier, value string, local bool, transaction bool) error { + if transaction && !local { + // When transaction == true, then local must also be true. + // We should never hit this condition, as this is an indication of a bug in the driver code. + return status.Errorf(codes.FailedPrecondition, "transaction properties must be set as a local value") + } extension, name, err := toExtensionAndName(identifier) if err != nil { return err } if local { - return c.state.SetLocalValue(extension, name, value) + return c.state.SetLocalValue(extension, name, value, transaction) } return c.state.SetValue(extension, name, value, connectionstate.ContextUser) } @@ -1011,8 +1011,10 @@ func (c *conn) options(reset bool) *ExecOptions { TransactionTag: c.TransactionTag(), IsolationLevel: toProtoIsolationLevelOrDefault(c.IsolationLevel()), ReadLockMode: c.ReadLockMode(), + CommitPriority: propertyCommitPriority.GetValueOrDefault(c.state), CommitOptions: spanner.CommitOptions{ - MaxCommitDelay: c.maxCommitDelayPointer(), + MaxCommitDelay: c.maxCommitDelayPointer(), + ReturnCommitStats: propertyReturnCommitStats.GetValueOrDefault(c.state), }, }, PartitionedQueryOptions: PartitionedQueryOptions{}, @@ -1045,16 +1047,43 @@ func (c *conn) resetTransactionForRetry(ctx context.Context, errDuringCommit boo } func (c *conn) withTempTransactionOptions(options *ReadWriteTransactionOptions) { - c.tempTransactionOptions = options + if options == nil { + return + } + c.tempTransactionCloseFunc = options.close + // Start a transaction for the connection state, so we can set the transaction options + // as local options in the current transaction. + _ = c.state.Begin() + if options.DisableInternalRetries { + _ = propertyRetryAbortsInternally.SetLocalValue(c.state, !options.DisableInternalRetries) + } + if options.TransactionOptions.BeginTransactionOption != spanner.DefaultBeginTransaction { + _ = propertyBeginTransactionOption.SetLocalValue(c.state, options.TransactionOptions.BeginTransactionOption) + } + if options.TransactionOptions.CommitOptions.MaxCommitDelay != nil { + _ = propertyMaxCommitDelay.SetLocalValue(c.state, *options.TransactionOptions.CommitOptions.MaxCommitDelay) + } + if options.TransactionOptions.CommitOptions.ReturnCommitStats { + _ = propertyReturnCommitStats.SetLocalValue(c.state, options.TransactionOptions.CommitOptions.ReturnCommitStats) + } + if options.TransactionOptions.TransactionTag != "" { + _ = propertyTransactionTag.SetLocalValue(c.state, options.TransactionOptions.TransactionTag) + } + if options.TransactionOptions.ReadLockMode != spannerpb.TransactionOptions_ReadWrite_READ_LOCK_MODE_UNSPECIFIED { + _ = propertyReadLockMode.SetLocalValue(c.state, options.TransactionOptions.ReadLockMode) + } + if options.TransactionOptions.IsolationLevel != spannerpb.TransactionOptions_ISOLATION_LEVEL_UNSPECIFIED { + _ = propertyIsolationLevel.SetLocalValue(c.state, toSqlIsolationLevelOrDefault(options.TransactionOptions.IsolationLevel)) + } + if options.TransactionOptions.ExcludeTxnFromChangeStreams { + _ = propertyExcludeTxnFromChangeStreams.SetLocalValue(c.state, options.TransactionOptions.ExcludeTxnFromChangeStreams) + } + if options.TransactionOptions.CommitPriority != spannerpb.RequestOptions_PRIORITY_UNSPECIFIED { + _ = propertyCommitPriority.SetLocalValue(c.state, options.TransactionOptions.CommitPriority) + } } func (c *conn) getTransactionOptions(execOptions *ExecOptions) ReadWriteTransactionOptions { - if c.tempTransactionOptions != nil { - defer func() { c.tempTransactionOptions = nil }() - opts := *c.tempTransactionOptions - opts.TransactionOptions.BeginTransactionOption = c.convertDefaultBeginTransactionOption(opts.TransactionOptions.BeginTransactionOption) - return opts - } txOpts := ReadWriteTransactionOptions{ TransactionOptions: execOptions.TransactionOptions, DisableInternalRetries: !c.RetryAbortsInternally(), @@ -1075,28 +1104,39 @@ func (c *conn) getTransactionOptions(execOptions *ExecOptions) ReadWriteTransact } func (c *conn) withTempReadOnlyTransactionOptions(options *ReadOnlyTransactionOptions) { - c.tempReadOnlyTransactionOptions = options + if options == nil { + return + } + c.tempTransactionCloseFunc = options.close + // Start a transaction for the connection state, so we can set the transaction options + // as local options in the current transaction. + _ = c.state.Begin() + if options.BeginTransactionOption != spanner.DefaultBeginTransaction { + _ = propertyBeginTransactionOption.SetLocalValue(c.state, options.BeginTransactionOption) + } + if options.TimestampBound.String() != "(strong)" { + _ = propertyReadOnlyStaleness.SetLocalValue(c.state, options.TimestampBound) + } } func (c *conn) getReadOnlyTransactionOptions() ReadOnlyTransactionOptions { - if c.tempReadOnlyTransactionOptions != nil { - defer func() { c.tempReadOnlyTransactionOptions = nil }() - opts := *c.tempReadOnlyTransactionOptions - opts.BeginTransactionOption = c.convertDefaultBeginTransactionOption(opts.BeginTransactionOption) - return opts - } return ReadOnlyTransactionOptions{TimestampBound: c.ReadOnlyStaleness(), BeginTransactionOption: c.convertDefaultBeginTransactionOption(propertyBeginTransactionOption.GetValueOrDefault(c.state))} } func (c *conn) withTempBatchReadOnlyTransactionOptions(options *BatchReadOnlyTransactionOptions) { - c.tempBatchReadOnlyTransactionOptions = options + if options == nil { + return + } + c.tempTransactionCloseFunc = options.close + // Start a transaction for the connection state, so we can set the transaction options + // as local options in the current transaction. + _ = c.state.Begin() + if options.TimestampBound.String() != "(strong)" { + _ = propertyReadOnlyStaleness.SetLocalValue(c.state, options.TimestampBound) + } } func (c *conn) getBatchReadOnlyTransactionOptions() BatchReadOnlyTransactionOptions { - if c.tempBatchReadOnlyTransactionOptions != nil { - defer func() { c.tempBatchReadOnlyTransactionOptions = nil }() - return *c.tempBatchReadOnlyTransactionOptions - } return BatchReadOnlyTransactionOptions{TimestampBound: c.ReadOnlyStaleness()} } @@ -1108,7 +1148,6 @@ func (c *conn) BeginReadOnlyTransaction(ctx context.Context, options *ReadOnlyTr c.withTempReadOnlyTransactionOptions(options) tx, err := c.BeginTx(ctx, driver.TxOptions{ReadOnly: true}) if err != nil { - c.withTempReadOnlyTransactionOptions(nil) return nil, err } return tx, nil @@ -1122,7 +1161,6 @@ func (c *conn) BeginReadWriteTransaction(ctx context.Context, options *ReadWrite c.withTempTransactionOptions(options) tx, err := c.BeginTx(ctx, driver.TxOptions{}) if err != nil { - c.withTempTransactionOptions(nil) return nil, err } return tx, nil @@ -1133,6 +1171,13 @@ func (c *conn) Begin() (driver.Tx, error) { } func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver.Tx, error) { + defer func() { + c.tempTransactionCloseFunc = nil + }() + return c.beginTx(ctx, driverOpts, c.tempTransactionCloseFunc) +} + +func (c *conn) beginTx(ctx context.Context, driverOpts driver.TxOptions, closeFunc func()) (driver.Tx, error) { if c.resetForRetry { c.resetForRetry = false return c.tx, nil @@ -1141,9 +1186,15 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver defer func() { if c.tx != nil { _ = c.state.Begin() + } else { + // Rollback in case the connection state transaction was started before this function + // was called, for example if the caller set temporary transaction options. + _ = c.state.Rollback() } }() + // TODO: Delay the actual determination of the transaction type until the first query. + // This is required in order to support SET TRANSACTION READ {ONLY | WRITE} readOnlyTxOpts := c.getReadOnlyTransactionOptions() batchReadOnlyTxOpts := c.getBatchReadOnlyTransactionOptions() if c.inTransaction() { @@ -1180,6 +1231,9 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver if batchReadOnly && !driverOpts.ReadOnly { return nil, status.Error(codes.InvalidArgument, "levelBatchReadOnly can only be used for read-only transactions") } + if closeFunc == nil { + closeFunc = func() {} + } if driverOpts.ReadOnly { var logger *slog.Logger @@ -1188,6 +1242,8 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver if batchReadOnly { logger = c.logger.With("tx", "batchro") var err error + // BatchReadOnly transactions (currently) do not support inline-begin. + // This means that the transaction options must be supplied here, and not through a callback. bo, err = c.client.BatchReadOnlyTransaction(ctx, batchReadOnlyTxOpts.TimestampBound) if err != nil { return nil, err @@ -1195,19 +1251,14 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver ro = &bo.ReadOnlyTransaction } else { logger = c.logger.With("tx", "ro") - ro = c.client.ReadOnlyTransaction().WithBeginTransactionOption(readOnlyTxOpts.BeginTransactionOption).WithTimestampBound(readOnlyTxOpts.TimestampBound) + ro = c.client.ReadOnlyTransaction().WithBeginTransactionOption(readOnlyTxOpts.BeginTransactionOption) } c.tx = &readOnlyTransaction{ roTx: ro, boTx: bo, logger: logger, close: func(result txResult) { - if batchReadOnlyTxOpts.close != nil { - batchReadOnlyTxOpts.close() - } - if readOnlyTxOpts.close != nil { - readOnlyTxOpts.close() - } + closeFunc() if result == txResultCommit { _ = c.state.Commit() } else { @@ -1215,22 +1266,23 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver } c.tx = nil }, + timestampBoundCallback: func() spanner.TimestampBound { + return propertyReadOnlyStaleness.GetValueOrDefault(c.state) + }, } return c.tx, nil } + // These options are only used to determine how to start the transaction. + // All other options are fetched in a callback that is called when the transaction is actually started. + // That callback reads all transaction options from the connection state at that moment. This allows + // applications to execute a series of statement like this: + // BEGIN TRANSACTION; + // SET LOCAL transaction_tag='my_tag'; + // SET LOCAL commit_priority=LOW; + // INSERT INTO my_table ... -- This starts the transaction with the options above included. opts := spanner.TransactionOptions{} - if c.tempTransactionOptions != nil { - opts = c.tempTransactionOptions.TransactionOptions - } - opts.BeginTransactionOption = c.convertDefaultBeginTransactionOption(opts.BeginTransactionOption) - tempCloseFunc := func() {} - if c.tempTransactionOptions != nil && c.tempTransactionOptions.close != nil { - tempCloseFunc = c.tempTransactionOptions.close - } - if !disableRetryAborts && c.tempTransactionOptions != nil { - disableRetryAborts = c.tempTransactionOptions.DisableInternalRetries - } + opts.BeginTransactionOption = c.convertDefaultBeginTransactionOption(propertyBeginTransactionOption.GetValueOrDefault(c.state)) tx, err := spanner.NewReadWriteStmtBasedTransactionWithCallbackForOptions(ctx, c.client, opts, func() spanner.TransactionOptions { defer func() { @@ -1249,7 +1301,7 @@ func (c *conn) BeginTx(ctx context.Context, driverOpts driver.TxOptions) (driver logger: logger, rwTx: tx, close: func(result txResult, commitResponse *spanner.CommitResponse, commitErr error) { - tempCloseFunc() + closeFunc() c.prevTx = c.tx c.tx = nil if commitErr == nil { diff --git a/connection_properties.go b/connection_properties.go index be6716b7..6d65e02e 100644 --- a/connection_properties.go +++ b/connection_properties.go @@ -228,6 +228,24 @@ var propertyDecodeToNativeArrays = createConnectionProperty( // Transaction connection properties. // ------------------------------------------------------------------------------------------------ +var propertyTransactionReadOnly = createConnectionProperty( + "transaction_read_only", + "transaction_read_only is the default read-only mode for transactions on this connection.", + false, + false, + nil, + connectionstate.ContextUser, + connectionstate.ConvertBool, +) +var propertyTransactionDeferrable = createConnectionProperty( + "transaction_deferrable", + "transaction_deferrable is a no-op on Spanner. It is defined in this driver for compatibility with PostgreSQL.", + false, + false, + nil, + connectionstate.ContextUser, + connectionstate.ConvertBool, +) var propertyExcludeTxnFromChangeStreams = createConnectionProperty( "exclude_txn_from_change_streams", "exclude_txn_from_change_streams determines whether transactions on this connection should be excluded from "+ @@ -257,6 +275,27 @@ var propertyMaxCommitDelay = createConnectionProperty( connectionstate.ContextUser, connectionstate.ConvertDuration, ) +var propertyCommitPriority = createConnectionProperty( + "commit_priority", + "Sets the priority for commit RPC invocations from this connection (HIGH/MEDIUM/LOW/UNSPECIFIED). "+ + "The default is UNSPECIFIED.", + spannerpb.RequestOptions_PRIORITY_UNSPECIFIED, + false, + nil, + connectionstate.ContextUser, + func(value string) (spannerpb.RequestOptions_Priority, error) { + return parseRpcPriority(value) + }, +) +var propertyReturnCommitStats = createConnectionProperty( + "return_commit_stats", + "return_commit_stats determines whether transactions should request Spanner to return commit statistics.", + false, + false, + nil, + connectionstate.ContextUser, + connectionstate.ConvertBool, +) // ------------------------------------------------------------------------------------------------ // Statement connection properties. @@ -286,6 +325,17 @@ var propertyEndpoint = createConnectionProperty( connectionstate.ContextStartup, connectionstate.ConvertString, ) +var propertyAuthority = createConnectionProperty( + "authority", + "The expected server name in the TLS handshake. By default, the endpoint hostname is used. This option "+ + "is useful when connecting to Spanner via Google Private Connect or other custom endpoints where the "+ + "endpoint hostname does not match the server’s TLS certificate.", + "", + false, + nil, + connectionstate.ContextStartup, + connectionstate.ConvertString, +) var propertyCredentials = createConnectionProperty( "credentials", "The location of the credentials file to use for this connection. If neither this property or encoded "+ diff --git a/connectionstate/connection_state.go b/connectionstate/connection_state.go index 6fd7131d..77417eea 100644 --- a/connectionstate/connection_state.go +++ b/connectionstate/connection_state.go @@ -131,7 +131,10 @@ func (cs *ConnectionState) SetValue(extension, name, value string, context Conte return cs.setValue(extension, name, value, context, false) } -func (cs *ConnectionState) SetLocalValue(extension, name, value string) error { +func (cs *ConnectionState) SetLocalValue(extension, name, value string, isSetTransaction bool) error { + if isSetTransaction && !cs.inTransaction { + return status.Error(codes.FailedPrecondition, "SET TRANSACTION can only be used in transaction blocks") + } return cs.setValue(extension, name, value, ContextUser, true) } diff --git a/driver.go b/driver.go index 15cec71a..7ac7400f 100644 --- a/driver.go +++ b/driver.go @@ -51,7 +51,7 @@ import ( "google.golang.org/protobuf/proto" ) -const userAgent = "go-sql-spanner/1.18.0" // x-release-please-version +const userAgent = "go-sql-spanner/1.19.0" // x-release-please-version const gormModule = "github.com/googleapis/go-gorm-spanner" const gormUserAgent = "go-gorm-spanner" @@ -372,6 +372,10 @@ type ConnectorConfig struct { // Leave this empty to use the standard Spanner API endpoint. Host string + // The expected server name in the TLS handshake. + // Leave this empty to use the endpoint hostname. + Authority string + // Project, Instance, and Database identify the database that the connector // should create connections for. Project string @@ -568,6 +572,10 @@ func createConnector(d *Driver, connectorConfig ConnectorConfig) (*connector, er if connectorConfig.Host != "" { opts = append(opts, option.WithEndpoint(connectorConfig.Host)) } + assignPropertyValueIfExists(state, propertyAuthority, &connectorConfig.Authority) + if connectorConfig.Authority != "" { + opts = append(opts, option.WithGRPCDialOption(grpc.WithAuthority(connectorConfig.Authority))) + } if val := propertyCredentials.GetValueOrDefault(state); val != "" { opts = append(opts, option.WithCredentialsFile(val)) } @@ -1148,7 +1156,6 @@ func BeginReadWriteTransaction(ctx context.Context, db *sql.DB, options ReadWrit } tx, err := conn.BeginTx(ctx, &sql.TxOptions{}) if err != nil { - clearTempReadWriteTransactionOptions(conn) return nil, err } return tx, nil @@ -1166,11 +1173,6 @@ func withTempReadWriteTransactionOptions(conn *sql.Conn, options *ReadWriteTrans }) } -func clearTempReadWriteTransactionOptions(conn *sql.Conn) { - _ = withTempReadWriteTransactionOptions(conn, nil) - _ = conn.Close() -} - // ReadOnlyTransactionOptions can be used to create a read-only transaction // on a Spanner connection. type ReadOnlyTransactionOptions struct { @@ -1529,6 +1531,24 @@ func toProtoIsolationLevelOrDefault(level sql.IsolationLevel) spannerpb.Transact return res } +func toSqlIsolationLevel(level spannerpb.TransactionOptions_IsolationLevel) (sql.IsolationLevel, error) { + switch level { + case spannerpb.TransactionOptions_ISOLATION_LEVEL_UNSPECIFIED: + return sql.LevelDefault, nil + case spannerpb.TransactionOptions_SERIALIZABLE: + return sql.LevelSerializable, nil + case spannerpb.TransactionOptions_REPEATABLE_READ: + return sql.LevelRepeatableRead, nil + default: + } + return sql.LevelDefault, spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "invalid or unsupported isolation level: %v", level)) +} + +func toSqlIsolationLevelOrDefault(level spannerpb.TransactionOptions_IsolationLevel) sql.IsolationLevel { + res, _ := toSqlIsolationLevel(level) + return res +} + type spannerIsolationLevel sql.IsolationLevel const ( diff --git a/driver_with_mockserver_test.go b/driver_with_mockserver_test.go index ac9cbf79..209c1fa1 100644 --- a/driver_with_mockserver_test.go +++ b/driver_with_mockserver_test.go @@ -5076,7 +5076,7 @@ func TestBeginReadWriteTransaction(t *testing.T) { t.Fatalf("missing transaction for ExecuteSqlRequest") } if req.Transaction.GetId() == nil { - t.Fatalf("missing begin selector for ExecuteSqlRequest") + t.Fatalf("missing ID selector for ExecuteSqlRequest") } if g, w := req.RequestOptions.TransactionTag, tag; g != w { t.Fatalf("transaction tag mismatch\n Got: %v\nWant: %v", g, w) diff --git a/examples/go.mod b/examples/go.mod index e74467ed..c5ed264a 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -7,20 +7,20 @@ toolchain go1.24.3 replace github.com/googleapis/go-sql-spanner => ../ require ( - cloud.google.com/go v0.122.0 - cloud.google.com/go/spanner v1.85.1 + cloud.google.com/go v0.123.0 + cloud.google.com/go/spanner v1.86.0 github.com/docker/docker v28.3.3+incompatible github.com/docker/go-connections v0.5.0 github.com/googleapis/go-sql-spanner v1.16.2 github.com/testcontainers/testcontainers-go v0.38.0 - google.golang.org/api v0.249.0 + google.golang.org/api v0.251.0 ) require ( cel.dev/expr v0.24.0 // indirect cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.8.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect @@ -91,17 +91,17 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.12.0 // indirect + golang.org/x/crypto v0.42.0 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/oauth2 v0.31.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.13.0 // indirect google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.75.1 // indirect - google.golang.org/protobuf v1.36.9 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 52c55eb2..f6ba2e7b 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= -cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= -cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -526,8 +526,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.85.1 h1:cJx1ZD//C2QIfFQl8hSTn4twL8amAXtnayyflRIjj40= -cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= +cloud.google.com/go/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -1052,8 +1052,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1168,8 +1168,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1199,8 +1199,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1217,8 +1217,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1300,8 +1300,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1310,8 +1310,8 @@ golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1328,16 +1328,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1476,8 +1476,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w= -google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ= +google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= +google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1621,8 +1621,8 @@ google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyT google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1684,8 +1684,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/go.mod b/go.mod index a0bdb3ca..3311c949 100644 --- a/go.mod +++ b/go.mod @@ -5,25 +5,25 @@ go 1.24.0 toolchain go1.25.1 require ( - cloud.google.com/go v0.122.0 + cloud.google.com/go v0.123.0 cloud.google.com/go/longrunning v0.6.7 - cloud.google.com/go/spanner v1.85.1 + cloud.google.com/go/spanner v1.86.0 github.com/golang/protobuf v1.5.4 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.15.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - google.golang.org/api v0.249.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 + google.golang.org/api v0.251.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 google.golang.org/grpc v1.75.1 - google.golang.org/protobuf v1.36.9 + google.golang.org/protobuf v1.36.10 ) require ( cel.dev/expr v0.24.0 // indirect cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.8.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect @@ -52,13 +52,13 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.12.0 // indirect + golang.org/x/crypto v0.42.0 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/oauth2 v0.31.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.13.0 // indirect google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect ) diff --git a/go.sum b/go.sum index facf0032..37cdcdc0 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= -cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= -cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -526,8 +526,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.85.1 h1:cJx1ZD//C2QIfFQl8hSTn4twL8amAXtnayyflRIjj40= -cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= +cloud.google.com/go/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -955,8 +955,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1071,8 +1071,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1102,8 +1102,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1120,8 +1120,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1199,8 +1199,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1225,16 +1225,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1371,8 +1371,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w= -google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ= +google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= +google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1516,8 +1516,8 @@ google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyT google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1579,8 +1579,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/parser/simple_parser.go b/parser/simple_parser.go index 9a2da379..e8fef032 100644 --- a/parser/simple_parser.go +++ b/parser/simple_parser.go @@ -290,6 +290,16 @@ func (p *simpleParser) eatKeywords(keywords []string) bool { return true } +// peekKeyword checks if the next keyword is the given keyword. +// The position of the parser is not updated. +func (p *simpleParser) peekKeyword(keyword string) bool { + pos := p.pos + defer func() { + p.pos = pos + }() + return p.eatKeyword(keyword) +} + // eatKeyword eats the given keyword at the current position of the parser if it exists // and returns true if the keyword was found. Otherwise, it returns false. func (p *simpleParser) eatKeyword(keyword string) bool { @@ -323,8 +333,8 @@ func (p *simpleParser) readKeyword() string { if isSpace(p.sql[p.pos]) { break } - // Only upper/lower-case letters are allowed in keywords. - if !((p.sql[p.pos] >= 'A' && p.sql[p.pos] <= 'Z') || (p.sql[p.pos] >= 'a' && p.sql[p.pos] <= 'z')) { + // Only upper/lower-case letters and underscores are allowed in keywords. + if !((p.sql[p.pos] >= 'A' && p.sql[p.pos] <= 'Z') || (p.sql[p.pos] >= 'a' && p.sql[p.pos] <= 'z')) && p.sql[p.pos] != '_' { break } } diff --git a/parser/statement_parser_test.go b/parser/statement_parser_test.go index ed50be2b..2ab64399 100644 --- a/parser/statement_parser_test.go +++ b/parser/statement_parser_test.go @@ -2135,6 +2135,10 @@ func TestReadKeyword(t *testing.T) { input: "Select from my_table", want: "Select", }, + { + input: "statement_tag", + want: "statement_tag", + }, } statementParser, err := NewStatementParser(databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, 1000) if err != nil { @@ -2404,6 +2408,36 @@ func TestCachedParamsAreImmutable(t *testing.T) { } } +func TestPeekKeyword(t *testing.T) { + t.Parallel() + + parser, err := NewStatementParser(databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, 1000) + if err != nil { + t.Fatal(err) + } + sp := &simpleParser{sql: []byte("select * from foo"), statementParser: parser} + if !sp.peekKeyword("select") { + t.Fatal("peekKeyword should have returned true") + } + if g, w := sp.pos, 0; g != w { + t.Fatalf("position mismatch\n Got: %v\nWant: %v", g, w) + } + + if !sp.eatKeyword("select") { + t.Fatal("eatKeyword should have returned true") + } + if !sp.eatToken('*') { + t.Fatal("eatToken should have returned true") + } + pos := sp.pos + if !sp.peekKeyword("from") { + t.Fatal("peekKeyword should have returned true") + } + if g, w := sp.pos, pos; g != w { + t.Fatalf("position mismatch\n Got: %v\nWant: %v", g, w) + } +} + func TestEatKeyword(t *testing.T) { t.Parallel() diff --git a/parser/statements.go b/parser/statements.go index 2dc1ce93..d45b01e3 100644 --- a/parser/statements.go +++ b/parser/statements.go @@ -15,6 +15,8 @@ package parser import ( + "fmt" + "cloud.google.com/go/spanner/admin/database/apiv1/databasepb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -142,11 +144,27 @@ func (s *ParsedShowStatement) parse(parser *StatementParser, query string) error // ParsedSetStatement is a statement of the form // SET [SESSION | LOCAL] [my_extension.]my_property {=|to} +// +// It also covers statements of the form SET TRANSACTION. This is a +// synonym for SET LOCAL, but is only supported for a specific set of +// properties, and may only be executed before a transaction has been +// activated. Examples include: +// SET TRANSACTION READ ONLY +// SET TRANSACTION ISOLATION LEVEL [SERIALIZABLE | REPEATABLE READ] +// +// One SET statement can set more than one property. type ParsedSetStatement struct { - query string - Identifier Identifier - Literal Literal - IsLocal bool + query string + // Identifiers contains the properties that are being set. The number of elements in this slice + // must be equal to the number of Literals. + Identifiers []Identifier + // Literals contains the values that should be set for the properties. + Literals []Literal + // IsLocal indicates whether this is a SET LOCAL statement or not. + IsLocal bool + // IsTransaction indicates whether this is a SET TRANSACTION statement or not. + // IsTransaction automatically also implies IsLocal. + IsTransaction bool } func (s *ParsedSetStatement) Name() string { @@ -165,10 +183,17 @@ func (s *ParsedSetStatement) parse(parser *StatementParser, query string) error return status.Errorf(codes.InvalidArgument, "syntax error: expected SET") } isLocal := sp.eatKeyword("LOCAL") - if !isLocal && parser.Dialect == databasepb.DatabaseDialect_POSTGRESQL { + isTransaction := false + if !isLocal { + isTransaction = sp.eatKeyword("TRANSACTION") + } + if !isLocal && !isTransaction && parser.Dialect == databasepb.DatabaseDialect_POSTGRESQL { // Just eat and ignore the SESSION keyword if it exists, as SESSION is the default. _ = sp.eatKeyword("SESSION") } + if isTransaction { + return s.parseSetTransaction(sp, query) + } identifier, err := sp.eatIdentifier() if err != nil { return err @@ -191,12 +216,108 @@ func (s *ParsedSetStatement) parse(parser *StatementParser, query string) error return status.Errorf(codes.InvalidArgument, "unexpected tokens at position %d in %q", sp.pos, sp.sql) } s.query = query - s.Identifier = identifier - s.Literal = literalValue + s.Identifiers = []Identifier{identifier} + s.Literals = []Literal{literalValue} s.IsLocal = isLocal return nil } +func (s *ParsedSetStatement) parseSetTransaction(sp *simpleParser, query string) error { + if !sp.hasMoreTokens() { + return status.Errorf(codes.InvalidArgument, "syntax error: missing TRANSACTION OPTION, expected one of ISOLATION LEVEL, READ WRITE, or READ ONLY") + } + s.query = query + s.IsLocal = true + s.IsTransaction = true + + var err error + s.Identifiers, s.Literals, err = parseTransactionOptions(sp) + if err != nil { + return err + } + return nil +} + +func parseTransactionOptions(sp *simpleParser) ([]Identifier, []Literal, error) { + identifiers := make([]Identifier, 0, 2) + literals := make([]Literal, 0, 2) + var err error + for { + if sp.peekKeyword("ISOLATION") { + identifiers, literals, err = parseTransactionIsolationLevel(sp, identifiers, literals) + if err != nil { + return nil, nil, err + } + } else if sp.peekKeyword("READ") { + identifiers, literals, err = parseTransactionMode(sp, identifiers, literals) + if err != nil { + return nil, nil, err + } + } else if sp.statementParser.Dialect == databasepb.DatabaseDialect_POSTGRESQL && (sp.peekKeyword("DEFERRABLE") || sp.peekKeyword("NOT")) { + // https://www.postgresql.org/docs/current/sql-set-transaction.html + identifiers, literals, err = parseTransactionDeferrable(sp, identifiers, literals) + if err != nil { + return nil, nil, err + } + } else { + return nil, nil, status.Error(codes.InvalidArgument, "invalid TRANSACTION option, expected one of ISOLATION LEVEL, READ WRITE, or READ ONLY") + } + if !sp.hasMoreTokens() { + return identifiers, literals, nil + } + // Eat and ignore any commas separating the various options. + sp.eatToken(',') + } +} + +func parseTransactionIsolationLevel(sp *simpleParser, identifiers []Identifier, literals []Literal) ([]Identifier, []Literal, error) { + if !sp.eatKeywords([]string{"ISOLATION", "LEVEL"}) { + return nil, nil, status.Errorf(codes.InvalidArgument, "syntax error: expected ISOLATION LEVEL") + } + var value Literal + if sp.eatKeyword("SERIALIZABLE") { + value = Literal{Value: "serializable"} + } else if sp.eatKeywords([]string{"REPEATABLE", "READ"}) { + value = Literal{Value: "repeatable_read"} + } else { + return nil, nil, status.Errorf(codes.InvalidArgument, "syntax error: expected SERIALIZABLE OR REPETABLE READ") + } + + identifiers = append(identifiers, Identifier{Parts: []string{"isolation_level"}}) + literals = append(literals, value) + return identifiers, literals, nil +} + +func parseTransactionMode(sp *simpleParser, identifiers []Identifier, literals []Literal) ([]Identifier, []Literal, error) { + readOnly := false + if sp.eatKeywords([]string{"READ", "ONLY"}) { + readOnly = true + } else if sp.eatKeywords([]string{"READ", "WRITE"}) { + readOnly = false + } else { + return nil, nil, status.Errorf(codes.InvalidArgument, "syntax error: expected READ ONLY or READ WRITE") + } + + identifiers = append(identifiers, Identifier{Parts: []string{"transaction_read_only"}}) + literals = append(literals, Literal{Value: fmt.Sprintf("%v", readOnly)}) + return identifiers, literals, nil +} + +func parseTransactionDeferrable(sp *simpleParser, identifiers []Identifier, literals []Literal) ([]Identifier, []Literal, error) { + deferrable := false + if sp.eatKeywords([]string{"NOT", "DEFERRABLE"}) { + deferrable = false + } else if sp.eatKeyword("DEFERRABLE") { + deferrable = true + } else { + return nil, nil, status.Errorf(codes.InvalidArgument, "syntax error: expected [NOT] DEFERRABLE") + } + + identifiers = append(identifiers, Identifier{Parts: []string{"transaction_deferrable"}}) + literals = append(literals, Literal{Value: fmt.Sprintf("%v", deferrable)}) + return identifiers, literals, nil +} + // ParsedResetStatement is a statement of the form // RESET [my_extension.]my_property type ParsedResetStatement struct { @@ -390,6 +511,12 @@ func (s *ParsedAbortBatchStatement) parse(parser *StatementParser, query string) type ParsedBeginStatement struct { query string + // Identifiers contains the transaction properties that were included in the BEGIN statement. E.g. the statement + // BEGIN TRANSACTION READ ONLY contains the transaction property 'transaction_read_only'. + Identifiers []Identifier + // Literals contains the transaction property values that were included in the BEGIN statement. E.g. the statement + // BEGIN TRANSACTION READ ONLY contains the value 'true' for the property 'transaction_read_only'. + Literals []Literal } func (s *ParsedBeginStatement) Name() string { @@ -402,8 +529,9 @@ func (s *ParsedBeginStatement) Query() string { func (s *ParsedBeginStatement) parse(parser *StatementParser, query string) error { // Parse a statement of the form - // GoogleSQL: BEGIN [TRANSACTION] + // GoogleSQL: BEGIN [TRANSACTION] [READ WRITE | READ ONLY | ISOLATION LEVEL {SERIALIZABLE | READ COMMITTED}] // PostgreSQL: {START | BEGIN} [{TRANSACTION | WORK}] (https://www.postgresql.org/docs/current/sql-begin.html) + // TODO: Support transaction modes in the BEGIN / START statement. sp := &simpleParser{sql: []byte(query), statementParser: parser} if sp.statementParser.Dialect == databasepb.DatabaseDialect_POSTGRESQL { if !sp.eatKeyword("START") && !sp.eatKeyword("BEGIN") { @@ -424,8 +552,13 @@ func (s *ParsedBeginStatement) parse(parser *StatementParser, query string) erro } if sp.hasMoreTokens() { - return status.Errorf(codes.InvalidArgument, "unexpected tokens at position %d in %q", sp.pos, sp.sql) + var err error + s.Identifiers, s.Literals, err = parseTransactionOptions(sp) + if err != nil { + return err + } } + s.query = query return nil } diff --git a/parser/statements_test.go b/parser/statements_test.go index a7bb1d1c..45361c74 100644 --- a/parser/statements_test.go +++ b/parser/statements_test.go @@ -15,6 +15,7 @@ package parser import ( + "fmt" "reflect" "strings" "testing" @@ -128,56 +129,218 @@ func TestParseSetStatement(t *testing.T) { type test struct { input string want ParsedSetStatement + onlyPg bool wantErr bool } tests := []test{ { input: "set my_property = 'foo'", want: ParsedSetStatement{ - query: "set my_property = 'foo'", - Identifier: Identifier{Parts: []string{"my_property"}}, - Literal: Literal{Value: "foo"}, + query: "set my_property = 'foo'", + Identifiers: []Identifier{{Parts: []string{"my_property"}}}, + Literals: []Literal{{Value: "foo"}}, }, }, { input: "set local my_property = 'foo'", want: ParsedSetStatement{ - query: "set local my_property = 'foo'", - Identifier: Identifier{Parts: []string{"my_property"}}, - Literal: Literal{Value: "foo"}, - IsLocal: true, + query: "set local my_property = 'foo'", + Identifiers: []Identifier{{Parts: []string{"my_property"}}}, + Literals: []Literal{{Value: "foo"}}, + IsLocal: true, }, }, { input: "set my_property = 1", want: ParsedSetStatement{ - query: "set my_property = 1", - Identifier: Identifier{Parts: []string{"my_property"}}, - Literal: Literal{Value: "1"}, + query: "set my_property = 1", + Identifiers: []Identifier{{Parts: []string{"my_property"}}}, + Literals: []Literal{{Value: "1"}}, }, }, { input: "set my_property = true", want: ParsedSetStatement{ - query: "set my_property = true", - Identifier: Identifier{Parts: []string{"my_property"}}, - Literal: Literal{Value: "true"}, + query: "set my_property = true", + Identifiers: []Identifier{{Parts: []string{"my_property"}}}, + Literals: []Literal{{Value: "true"}}, }, }, { input: "set \n -- comment \n my_property /* yet more comments */ = \ntrue/*comment*/ ", want: ParsedSetStatement{ - query: "set \n -- comment \n my_property /* yet more comments */ = \ntrue/*comment*/ ", - Identifier: Identifier{Parts: []string{"my_property"}}, - Literal: Literal{Value: "true"}, + query: "set \n -- comment \n my_property /* yet more comments */ = \ntrue/*comment*/ ", + Identifiers: []Identifier{{Parts: []string{"my_property"}}}, + Literals: []Literal{{Value: "true"}}, }, }, { input: "set \n -- comment \n a.b /* yet more comments */ =\n/*comment*/'value'/*comment*/ ", want: ParsedSetStatement{ - query: "set \n -- comment \n a.b /* yet more comments */ =\n/*comment*/'value'/*comment*/ ", - Identifier: Identifier{Parts: []string{"a", "b"}}, - Literal: Literal{Value: "value"}, + query: "set \n -- comment \n a.b /* yet more comments */ =\n/*comment*/'value'/*comment*/ ", + Identifiers: []Identifier{{Parts: []string{"a", "b"}}}, + Literals: []Literal{{Value: "value"}}, + }, + }, + { + input: "set transaction isolation level serializable", + want: ParsedSetStatement{ + query: "set transaction isolation level serializable", + Identifiers: []Identifier{{Parts: []string{"isolation_level"}}}, + Literals: []Literal{{Value: "serializable"}}, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction isolation serializable", + wantErr: true, + }, + { + input: "set transaction isolation level serializable foo", + wantErr: true, + }, + { + input: "set isolation level serializable", + wantErr: true, + }, + { + input: "set transaction isolation level serialisable", + wantErr: true, + }, + { + input: "set transaction isolation level repeatable read", + want: ParsedSetStatement{ + query: "set transaction isolation level repeatable read", + Identifiers: []Identifier{{Parts: []string{"isolation_level"}}}, + Literals: []Literal{{Value: "repeatable_read"}}, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction isolation level repeatable", + wantErr: true, + }, + { + input: "set transaction isolation level read", + wantErr: true, + }, + { + input: "set transaction isolation level repeatable read serializable", + wantErr: true, + }, + { + input: "set transaction isolation level serializable repeatable read", + wantErr: true, + }, + { + input: "set transaction read write", + want: ParsedSetStatement{ + query: "set transaction read write", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "false"}}, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction read write isolation level serializable", + want: ParsedSetStatement{ + query: "set transaction read write isolation level serializable", + Identifiers: []Identifier{ + {Parts: []string{"transaction_read_only"}}, + {Parts: []string{"isolation_level"}}, + }, + Literals: []Literal{ + {Value: "false"}, + {Value: "serializable"}, + }, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction read only, isolation level repeatable read", + want: ParsedSetStatement{ + query: "set transaction read only, isolation level repeatable read", + Identifiers: []Identifier{ + {Parts: []string{"transaction_read_only"}}, + {Parts: []string{"isolation_level"}}, + }, + Literals: []Literal{ + {Value: "true"}, + {Value: "repeatable_read"}, + }, + IsLocal: true, + IsTransaction: true, + }, + }, + { + onlyPg: true, + input: "set transaction read only, isolation level repeatable read not deferrable", + want: ParsedSetStatement{ + query: "set transaction read only, isolation level repeatable read not deferrable", + Identifiers: []Identifier{ + {Parts: []string{"transaction_read_only"}}, + {Parts: []string{"isolation_level"}}, + {Parts: []string{"transaction_deferrable"}}, + }, + Literals: []Literal{ + {Value: "true"}, + {Value: "repeatable_read"}, + {Value: "false"}, + }, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction read only", + want: ParsedSetStatement{ + query: "set transaction read only", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "true"}}, + IsLocal: true, + IsTransaction: true, + }, + }, + { + input: "set transaction read", + wantErr: true, + }, + { + input: "set transaction write", + wantErr: true, + }, + { + input: "set transaction read only write", + wantErr: true, + }, + { + input: "set transaction write only", + wantErr: true, + }, + { + onlyPg: true, + input: "set transaction deferrable", + want: ParsedSetStatement{ + query: "set transaction deferrable", + Identifiers: []Identifier{{Parts: []string{"transaction_deferrable"}}}, + Literals: []Literal{{Value: "true"}}, + IsLocal: true, + IsTransaction: true, + }, + }, + { + onlyPg: true, + input: "set transaction not deferrable", + want: ParsedSetStatement{ + query: "set transaction not deferrable", + Identifiers: []Identifier{{Parts: []string{"transaction_deferrable"}}}, + Literals: []Literal{{Value: "false"}}, + IsLocal: true, + IsTransaction: true, }, }, { @@ -205,31 +368,33 @@ func TestParseSetStatement(t *testing.T) { wantErr: true, }, } - parser, err := NewStatementParser(databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, 1000) - if err != nil { - t.Fatal(err) - } - keyword := "SET" - for _, test := range tests { - t.Run(test.input, func(t *testing.T) { - stmt, err := parseStatement(parser, keyword, test.input) - if test.wantErr { - if err == nil { - t.Fatalf("parseStatement(%q) should have failed", test.input) - } - } else { - if err != nil { - t.Fatal(err) + for _, dialect := range []databasepb.DatabaseDialect{databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, databasepb.DatabaseDialect_POSTGRESQL} { + parser, err := NewStatementParser(dialect, 1000) + if err != nil { + t.Fatal(err) + } + keyword := "SET" + for _, test := range tests { + t.Run(fmt.Sprintf("%s %s", dialect, test.input), func(t *testing.T) { + stmt, err := parseStatement(parser, keyword, test.input) + if test.wantErr || (test.onlyPg && dialect == databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL) { + if err == nil { + t.Fatalf("parseStatement(%q) should have failed", test.input) + } + } else { + if err != nil { + t.Fatal(err) + } + showStmt, ok := stmt.(*ParsedSetStatement) + if !ok { + t.Fatalf("parseStatement(%q) should have returned a *parsedSetStatement", test.input) + } + if !reflect.DeepEqual(*showStmt, test.want) { + t.Errorf("parseStatement(%q) = %v, want %v", test.input, *showStmt, test.want) + } } - showStmt, ok := stmt.(*ParsedSetStatement) - if !ok { - t.Fatalf("parseStatement(%q) should have returned a *parsedSetStatement", test.input) - } - if !reflect.DeepEqual(*showStmt, test.want) { - t.Errorf("parseStatement(%q) = %v, want %v", test.input, *showStmt, test.want) - } - } - }) + }) + } } } @@ -266,6 +431,38 @@ func TestParseBeginStatementGoogleSQL(t *testing.T) { input: "begin transaction foo", wantErr: true, }, + { + input: "begin read only", + want: ParsedBeginStatement{ + query: "begin read only", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "true"}}, + }, + }, + { + input: "begin read write", + want: ParsedBeginStatement{ + query: "begin read write", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "false"}}, + }, + }, + { + input: "begin transaction isolation level serializable", + want: ParsedBeginStatement{ + query: "begin transaction isolation level serializable", + Identifiers: []Identifier{{Parts: []string{"isolation_level"}}}, + Literals: []Literal{{Value: "serializable"}}, + }, + }, + { + input: "begin transaction isolation level repeatable read, read write", + want: ParsedBeginStatement{ + query: "begin transaction isolation level repeatable read, read write", + Identifiers: []Identifier{{Parts: []string{"isolation_level"}}, {Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "repeatable_read"}, {Value: "false"}}, + }, + }, } parser, err := NewStatementParser(databasepb.DatabaseDialect_GOOGLE_STANDARD_SQL, 1000) if err != nil { @@ -289,7 +486,7 @@ func TestParseBeginStatementGoogleSQL(t *testing.T) { t.Fatalf("parseStatement(%q) should have returned a *parsedBeginStatement", test.input) } if !reflect.DeepEqual(*showStmt, test.want) { - t.Errorf("parseStatement(%q) = %v, want %v", test.input, *showStmt, test.want) + t.Errorf("parseStatement(%q) mismatch\n Got: %v\nWant: %v", test.input, *showStmt, test.want) } } }) @@ -341,6 +538,56 @@ func TestParseBeginStatementPostgreSQL(t *testing.T) { query: "start work", }, }, + { + input: "start work read only", + want: ParsedBeginStatement{ + query: "start work read only", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "true"}}, + }, + }, + { + input: "begin read write", + want: ParsedBeginStatement{ + query: "begin read write", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}}, + Literals: []Literal{{Value: "false"}}, + }, + }, + { + input: "begin read write, isolation level repeatable read", + want: ParsedBeginStatement{ + query: "begin read write, isolation level repeatable read", + Identifiers: []Identifier{{Parts: []string{"transaction_read_only"}}, {Parts: []string{"isolation_level"}}}, + Literals: []Literal{{Value: "false"}, {Value: "repeatable_read"}}, + }, + }, + { + // Note that it is possible to set multiple conflicting transaction options in one statement. + // This statement for example sets the transaction to both read/write and read-only. + // The last option will take precedence, as these options are essentially the same as executing the + // following statements sequentially after the BEGIN TRANSACTION statement: + // SET TRANSACTION READ WRITE + // SET TRANSACTION ISOLATION LEVEL REPEATABLE READ + // SET TRANSACTION READ ONLY + // SET TRANSACTION DEFERRABLE + input: "begin transaction \nread write,\nisolation level repeatable read\nread only\ndeferrable", + want: ParsedBeginStatement{ + query: "begin transaction \nread write,\nisolation level repeatable read\nread only\ndeferrable", + Identifiers: []Identifier{ + {Parts: []string{"transaction_read_only"}}, + {Parts: []string{"isolation_level"}}, + {Parts: []string{"transaction_read_only"}}, + {Parts: []string{"transaction_deferrable"}}, + }, + Literals: []Literal{ + {Value: "false"}, + {Value: "repeatable_read"}, + {Value: "true"}, + {Value: "true"}, + }, + }, + }, { input: "start foo", wantErr: true, @@ -376,7 +623,7 @@ func TestParseBeginStatementPostgreSQL(t *testing.T) { t.Fatalf("parseStatement(%q) should have returned a *parsedBeginStatement", test.input) } if !reflect.DeepEqual(*showStmt, test.want) { - t.Errorf("parseStatement(%q) = %v, want %v", test.input, *showStmt, test.want) + t.Errorf("parseStatement(%q) mismatch\n Got: %v\nWant: %v", test.input, *showStmt, test.want) } } }) diff --git a/snippets/go.mod b/snippets/go.mod index fb8c5767..2dd835ea 100644 --- a/snippets/go.mod +++ b/snippets/go.mod @@ -7,18 +7,18 @@ toolchain go1.25.1 replace github.com/googleapis/go-sql-spanner => ../ require ( - cloud.google.com/go/spanner v1.85.1 - github.com/docker/docker v28.4.0+incompatible - github.com/googleapis/go-sql-spanner v1.18.0 + cloud.google.com/go/spanner v1.86.0 + github.com/docker/docker v28.5.0+incompatible + github.com/googleapis/go-sql-spanner v1.18.1 github.com/testcontainers/testcontainers-go v0.39.0 ) require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.122.0 // indirect + cloud.google.com/go v0.123.0 // indirect cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.8.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect @@ -90,18 +90,18 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect + golang.org/x/crypto v0.42.0 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/oauth2 v0.31.0 // indirect + golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.36.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.12.0 // indirect - google.golang.org/api v0.249.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.13.0 // indirect + google.golang.org/api v0.251.0 // indirect google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.75.1 // indirect - google.golang.org/protobuf v1.36.9 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/snippets/go.sum b/snippets/go.sum index f9b4e46c..064c23d0 100644 --- a/snippets/go.sum +++ b/snippets/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= -cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= -cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -526,8 +526,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.85.1 h1:cJx1ZD//C2QIfFQl8hSTn4twL8amAXtnayyflRIjj40= -cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= +cloud.google.com/go/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -688,8 +688,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk= -github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.5.0+incompatible h1:ZdSQoRUE9XxhFI/B8YLvhnEFMmYN9Pp8Egd2qcaFk1E= +github.com/docker/docker v28.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -1047,8 +1047,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1163,8 +1163,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1194,8 +1194,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1212,8 +1212,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1306,8 +1306,8 @@ golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1324,16 +1324,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1470,8 +1470,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w= -google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ= +google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= +google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1615,8 +1615,8 @@ google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyT google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1678,8 +1678,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/spannerlib/.gitignore b/spannerlib/.gitignore index f6dbcd3d..e3130ba8 100644 --- a/spannerlib/.gitignore +++ b/spannerlib/.gitignore @@ -1,3 +1,10 @@ spannerlib.h spannerlib.so grpc_server +vendor/bundle +shared/ +*.gem +.DS_Store +*.swp +ext/ +Gemfile.lock diff --git a/spannerlib/api/transaction_test.go b/spannerlib/api/transaction_test.go index 1f0ec81d..efb6c993 100644 --- a/spannerlib/api/transaction_test.go +++ b/spannerlib/api/transaction_test.go @@ -24,6 +24,7 @@ import ( "cloud.google.com/go/spanner/apiv1/spannerpb" "github.com/googleapis/go-sql-spanner/testutil" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func TestBeginAndCommit(t *testing.T) { @@ -409,3 +410,166 @@ func TestDdlInTransaction(t *testing.T) { t.Fatalf("ClosePool returned unexpected error: %v", err) } } + +func TestTransactionOptionsAsSqlStatements(t *testing.T) { + t.Parallel() + + ctx := context.Background() + server, teardown := setupMockServer(t) + defer teardown() + dsn := fmt.Sprintf("%s/projects/p/instances/i/databases/d?useplaintext=true", server.Address) + + poolId, err := CreatePool(ctx, dsn) + if err != nil { + t.Fatalf("CreatePool returned unexpected error: %v", err) + } + connId, err := CreateConnection(ctx, poolId) + if err != nil { + t.Fatalf("CreateConnection returned unexpected error: %v", err) + } + if err := BeginTransaction(ctx, poolId, connId, &spannerpb.TransactionOptions{}); err != nil { + t.Fatalf("BeginTransaction returned unexpected error: %v", err) + } + + // Set some local transaction options. + if rowsId, err := Execute(ctx, poolId, connId, &spannerpb.ExecuteSqlRequest{Sql: "set local transaction_tag = 'my_tag'"}); err != nil { + t.Fatalf("setting transaction_tag returned unexpected error: %v", err) + } else { + _ = CloseRows(ctx, poolId, connId, rowsId) + } + if rowsId, err := Execute(ctx, poolId, connId, &spannerpb.ExecuteSqlRequest{Sql: "set local retry_aborts_internally = false"}); err != nil { + t.Fatalf("setting retry_aborts_internally returned unexpected error: %v", err) + } else { + _ = CloseRows(ctx, poolId, connId, rowsId) + } + + // Execute a statement in the transaction. + if rowsId, err := Execute(ctx, poolId, connId, &spannerpb.ExecuteSqlRequest{Sql: testutil.UpdateBarSetFoo}); err != nil { + t.Fatalf("Execute returned unexpected error: %v", err) + } else { + _ = CloseRows(ctx, poolId, connId, rowsId) + } + + // Abort the transaction to verify that the retry_aborts_internally setting was respected. + server.TestSpanner.PutExecutionTime(testutil.MethodCommitTransaction, testutil.SimulatedExecutionTime{ + Errors: []error{status.Error(codes.Aborted, "Aborted")}, + }) + + // Commit the transaction. This should fail with an Aborted error. + if _, err := Commit(ctx, poolId, connId); err == nil { + t.Fatal("missing expected error") + } else { + if g, w := spanner.ErrCode(err), codes.Aborted; g != w { + t.Fatalf("error code mismatch\n Got: %v\nWant: %v", g, w) + } + } + + // Verify that the transaction_tag setting was respected. + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("Execute request count mismatch\n Got: %v\nWant: %v", g, w) + } + executeRequest := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if executeRequest.RequestOptions == nil { + t.Fatalf("Execute request options not set") + } + if g, w := executeRequest.RequestOptions.TransactionTag, "my_tag"; g != w { + t.Fatalf("TransactionTag mismatch\n Got: %v\nWant: %v", g, w) + } + commitRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.CommitRequest{})) + if g, w := len(commitRequests), 1; g != w { + t.Fatalf("Commit request count mismatch\n Got: %v\nWant: %v", g, w) + } + commitRequest := commitRequests[0].(*spannerpb.CommitRequest) + if commitRequest.RequestOptions == nil { + t.Fatalf("Commit request options not set") + } + if g, w := commitRequest.RequestOptions.TransactionTag, "my_tag"; g != w { + t.Fatalf("TransactionTag mismatch\n Got: %v\nWant: %v", g, w) + } + + if err := CloseConnection(ctx, poolId, connId); err != nil { + t.Fatalf("CloseConnection returned unexpected error: %v", err) + } + if err := ClosePool(ctx, poolId); err != nil { + t.Fatalf("ClosePool returned unexpected error: %v", err) + } +} + +func TestReadOnlyTransactionOptionsAsSqlStatements(t *testing.T) { + t.Parallel() + + ctx := context.Background() + server, teardown := setupMockServer(t) + defer teardown() + dsn := fmt.Sprintf("%s/projects/p/instances/i/databases/d?useplaintext=true", server.Address) + + poolId, err := CreatePool(ctx, dsn) + if err != nil { + t.Fatalf("CreatePool returned unexpected error: %v", err) + } + connId, err := CreateConnection(ctx, poolId) + if err != nil { + t.Fatalf("CreateConnection returned unexpected error: %v", err) + } + // Start a read-only transaction without any further options. + if err := BeginTransaction(ctx, poolId, connId, &spannerpb.TransactionOptions{ + Mode: &spannerpb.TransactionOptions_ReadOnly_{ + ReadOnly: &spannerpb.TransactionOptions_ReadOnly{}, + }, + }); err != nil { + t.Fatalf("BeginTransaction returned unexpected error: %v", err) + } + + // Set a local read-only transaction options. + if rowsId, err := Execute(ctx, poolId, connId, &spannerpb.ExecuteSqlRequest{Sql: "set local read_only_staleness = 'exact_staleness 10s'"}); err != nil { + t.Fatalf("setting read_only_staleness returned unexpected error: %v", err) + } else { + _ = CloseRows(ctx, poolId, connId, rowsId) + } + + // Execute a statement in the transaction. + if rowsId, err := Execute(ctx, poolId, connId, &spannerpb.ExecuteSqlRequest{Sql: testutil.SelectFooFromBar}); err != nil { + t.Fatalf("Execute returned unexpected error: %v", err) + } else { + _ = CloseRows(ctx, poolId, connId, rowsId) + } + + // Commit the transaction to end it. + if _, err := Commit(ctx, poolId, connId); err != nil { + t.Fatalf("commit returned unexpected error: %v", err) + } + + // Verify that the read-only staleness setting was used. + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("Execute request count mismatch\n Got: %v\nWant: %v", g, w) + } + executeRequest := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if executeRequest.GetTransaction() == nil || executeRequest.GetTransaction().GetBegin() == nil || executeRequest.GetTransaction().GetBegin().GetReadOnly() == nil { + t.Fatal("ExecuteRequest does not contain a BeginTransaction option") + } + + readOnly := executeRequest.GetTransaction().GetBegin().GetReadOnly() + if readOnly.GetExactStaleness() == nil { + t.Fatal("BeginTransaction does not contain a ExactStaleness option") + } + if g, w := readOnly.GetExactStaleness().GetSeconds(), int64(10); g != w { + t.Fatalf("read staleness mismatch\n Got: %v\nWant: %v", g, w) + } + + // There should be no commit requests, as committing a read-only transaction is a no-op on Spanner. + commitRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.CommitRequest{})) + if g, w := len(commitRequests), 0; g != w { + t.Fatalf("Commit request count mismatch\n Got: %v\nWant: %v", g, w) + } + + if err := CloseConnection(ctx, poolId, connId); err != nil { + t.Fatalf("CloseConnection returned unexpected error: %v", err) + } + if err := ClosePool(ctx, poolId); err != nil { + t.Fatalf("ClosePool returned unexpected error: %v", err) + } +} diff --git a/spannerlib/go.mod b/spannerlib/go.mod index e42baa6b..fca2a2b8 100644 --- a/spannerlib/go.mod +++ b/spannerlib/go.mod @@ -8,20 +8,21 @@ replace github.com/googleapis/go-sql-spanner => .. require ( cloud.google.com/go/longrunning v0.6.7 - cloud.google.com/go/spanner v1.85.1 + cloud.google.com/go/spanner v1.86.0 github.com/google/go-cmp v0.7.0 - github.com/googleapis/go-sql-spanner v1.18.0 + github.com/google/uuid v1.6.0 + github.com/googleapis/go-sql-spanner v1.18.1 google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c google.golang.org/grpc v1.75.1 - google.golang.org/protobuf v1.36.9 + google.golang.org/protobuf v1.36.10 ) require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.122.0 // indirect + cloud.google.com/go v0.123.0 // indirect cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.8.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect @@ -37,7 +38,6 @@ require ( github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -54,14 +54,14 @@ require ( go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.12.0 // indirect - google.golang.org/api v0.249.0 // indirect + golang.org/x/crypto v0.42.0 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/oauth2 v0.31.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.13.0 // indirect + google.golang.org/api v0.251.0 // indirect google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect ) diff --git a/spannerlib/go.sum b/spannerlib/go.sum index facf0032..37cdcdc0 100644 --- a/spannerlib/go.sum +++ b/spannerlib/go.sum @@ -38,8 +38,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= -cloud.google.com/go v0.122.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= -cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -526,8 +526,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.85.1 h1:cJx1ZD//C2QIfFQl8hSTn4twL8amAXtnayyflRIjj40= -cloud.google.com/go/spanner v1.85.1/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= +cloud.google.com/go/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= @@ -955,8 +955,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1071,8 +1071,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1102,8 +1102,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1120,8 +1120,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1199,8 +1199,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1225,16 +1225,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1371,8 +1371,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.249.0 h1:0VrsWAKzIZi058aeq+I86uIXbNhm9GxSHpbmZ92a38w= -google.golang.org/api v0.249.0/go.mod h1:dGk9qyI0UYPwO/cjt2q06LG/EhUpwZGdAbYF14wHHrQ= +google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8= +google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1516,8 +1516,8 @@ google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b h1:eZTgydvqZO44zyT google.golang.org/genproto v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:suyz2QBHQKlGIF92HEEsCfO1SwxXdk7PFLz+Zd9Uah4= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1579,8 +1579,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/spannerlib/grpc-server/build-dotnet-darwin-aarch64.sh b/spannerlib/grpc-server/build-dotnet-darwin-aarch64.sh new file mode 100755 index 00000000..3578601b --- /dev/null +++ b/spannerlib/grpc-server/build-dotnet-darwin-aarch64.sh @@ -0,0 +1,4 @@ +go build -o grpc_server server.go +chmod +x grpc_server +cp grpc_server ../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc/binaries/any/grpc_server +cp grpc_server ../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc/binaries/osx-arm64/grpc_server diff --git a/spannerlib/grpc-server/build-java-darwin-aarch64.sh b/spannerlib/grpc-server/build-java-darwin-aarch64.sh index 9b5e9d77..a14a7154 100755 --- a/spannerlib/grpc-server/build-java-darwin-aarch64.sh +++ b/spannerlib/grpc-server/build-java-darwin-aarch64.sh @@ -1,3 +1,4 @@ go build -o grpc_server server.go chmod +x grpc_server +mkdir -p ../wrappers/spannerlib-java/src/main/resources/darwin-aarch64 cp grpc_server ../wrappers/spannerlib-java/src/main/resources/darwin-aarch64/grpc_server diff --git a/spannerlib/grpc-server/build-protos.sh b/spannerlib/grpc-server/build-protos.sh index b9214ef3..d3721808 100755 --- a/spannerlib/grpc-server/build-protos.sh +++ b/spannerlib/grpc-server/build-protos.sh @@ -1,6 +1,5 @@ PATH="${PATH}:${HOME}/go/bin" -rm -rf googleapis/google/spannerlib || true -cp -r google/spannerlib googleapis/google/spannerlib +ln -sf "${PWD}"/google/spannerlib googleapis/google/spannerlib cd googleapis || exit 1 protoc \ --go_out=../ \ @@ -14,5 +13,13 @@ protoc \ --java-grpc_out=../../wrappers/spannerlib-java/src/main/java/ \ --java-grpc_opt=paths=source_relative \ google/spannerlib/v1/spannerlib.proto +protoc \ + --csharp_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \ + --plugin=protoc-gen-csharp_grpc=/Users/loite/.nuget/packages/grpc.tools/2.72.0/tools/macosx_x64/grpc_csharp_plugin \ + --csharp_grpc_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \ + --csharp_opt=file_extension=.g.cs \ + --csharp_grpc_opt=no_server \ + --proto_path=. \ + google/spannerlib/v1/spannerlib.proto cd .. || exit 1 -rm -rf googleapis/google/spannerlib +rm googleapis/google/spannerlib diff --git a/spannerlib/grpc-server/google/spannerlib/spannerlib b/spannerlib/grpc-server/google/spannerlib/spannerlib new file mode 120000 index 00000000..73970885 --- /dev/null +++ b/spannerlib/grpc-server/google/spannerlib/spannerlib @@ -0,0 +1 @@ +/Users/loite/GolandProjects/go-sql-spanner/spannerlib/grpc-server/google/spannerlib \ No newline at end of file diff --git a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.pb.go b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.pb.go index 7c738df4..3707b228 100644 --- a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.pb.go +++ b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.pb.go @@ -25,6 +25,86 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type InfoRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InfoRequest) Reset() { + *x = InfoRequest{} + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InfoRequest) ProtoMessage() {} + +func (x *InfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InfoRequest.ProtoReflect.Descriptor instead. +func (*InfoRequest) Descriptor() ([]byte, []int) { + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{0} +} + +type InfoResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InfoResponse) Reset() { + *x = InfoResponse{} + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InfoResponse) ProtoMessage() {} + +func (x *InfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InfoResponse.ProtoReflect.Descriptor instead. +func (*InfoResponse) Descriptor() ([]byte, []int) { + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{1} +} + +func (x *InfoResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + type CreatePoolRequest struct { state protoimpl.MessageState `protogen:"open.v1"` ConnectionString string `protobuf:"bytes,1,opt,name=connection_string,json=connectionString,proto3" json:"connection_string,omitempty"` @@ -34,7 +114,7 @@ type CreatePoolRequest struct { func (x *CreatePoolRequest) Reset() { *x = CreatePoolRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[0] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -46,7 +126,7 @@ func (x *CreatePoolRequest) String() string { func (*CreatePoolRequest) ProtoMessage() {} func (x *CreatePoolRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[0] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -59,7 +139,7 @@ func (x *CreatePoolRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatePoolRequest.ProtoReflect.Descriptor instead. func (*CreatePoolRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{0} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{2} } func (x *CreatePoolRequest) GetConnectionString() string { @@ -78,7 +158,7 @@ type CreateConnectionRequest struct { func (x *CreateConnectionRequest) Reset() { *x = CreateConnectionRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[1] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -90,7 +170,7 @@ func (x *CreateConnectionRequest) String() string { func (*CreateConnectionRequest) ProtoMessage() {} func (x *CreateConnectionRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[1] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -103,7 +183,7 @@ func (x *CreateConnectionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateConnectionRequest.ProtoReflect.Descriptor instead. func (*CreateConnectionRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{1} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{3} } func (x *CreateConnectionRequest) GetPool() *Pool { @@ -123,7 +203,7 @@ type ExecuteRequest struct { func (x *ExecuteRequest) Reset() { *x = ExecuteRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[2] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -135,7 +215,7 @@ func (x *ExecuteRequest) String() string { func (*ExecuteRequest) ProtoMessage() {} func (x *ExecuteRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[2] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -148,7 +228,7 @@ func (x *ExecuteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecuteRequest.ProtoReflect.Descriptor instead. func (*ExecuteRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{2} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{4} } func (x *ExecuteRequest) GetConnection() *Connection { @@ -175,7 +255,7 @@ type ExecuteBatchRequest struct { func (x *ExecuteBatchRequest) Reset() { *x = ExecuteBatchRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[3] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -187,7 +267,7 @@ func (x *ExecuteBatchRequest) String() string { func (*ExecuteBatchRequest) ProtoMessage() {} func (x *ExecuteBatchRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[3] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -200,7 +280,7 @@ func (x *ExecuteBatchRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecuteBatchRequest.ProtoReflect.Descriptor instead. func (*ExecuteBatchRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{3} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{5} } func (x *ExecuteBatchRequest) GetConnection() *Connection { @@ -227,7 +307,7 @@ type BeginTransactionRequest struct { func (x *BeginTransactionRequest) Reset() { *x = BeginTransactionRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[4] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -239,7 +319,7 @@ func (x *BeginTransactionRequest) String() string { func (*BeginTransactionRequest) ProtoMessage() {} func (x *BeginTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[4] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -252,7 +332,7 @@ func (x *BeginTransactionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginTransactionRequest.ProtoReflect.Descriptor instead. func (*BeginTransactionRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{4} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{6} } func (x *BeginTransactionRequest) GetConnection() *Connection { @@ -279,7 +359,7 @@ type WriteMutationsRequest struct { func (x *WriteMutationsRequest) Reset() { *x = WriteMutationsRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[5] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -291,7 +371,7 @@ func (x *WriteMutationsRequest) String() string { func (*WriteMutationsRequest) ProtoMessage() {} func (x *WriteMutationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[5] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -304,7 +384,7 @@ func (x *WriteMutationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteMutationsRequest.ProtoReflect.Descriptor instead. func (*WriteMutationsRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{5} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{7} } func (x *WriteMutationsRequest) GetConnection() *Connection { @@ -330,7 +410,7 @@ type Pool struct { func (x *Pool) Reset() { *x = Pool{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[6] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -342,7 +422,7 @@ func (x *Pool) String() string { func (*Pool) ProtoMessage() {} func (x *Pool) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[6] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -355,7 +435,7 @@ func (x *Pool) ProtoReflect() protoreflect.Message { // Deprecated: Use Pool.ProtoReflect.Descriptor instead. func (*Pool) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{6} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{8} } func (x *Pool) GetId() int64 { @@ -375,7 +455,7 @@ type Connection struct { func (x *Connection) Reset() { *x = Connection{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[7] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -387,7 +467,7 @@ func (x *Connection) String() string { func (*Connection) ProtoMessage() {} func (x *Connection) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[7] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -400,7 +480,7 @@ func (x *Connection) ProtoReflect() protoreflect.Message { // Deprecated: Use Connection.ProtoReflect.Descriptor instead. func (*Connection) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{7} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{9} } func (x *Connection) GetPool() *Pool { @@ -427,7 +507,7 @@ type Rows struct { func (x *Rows) Reset() { *x = Rows{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[8] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -439,7 +519,7 @@ func (x *Rows) String() string { func (*Rows) ProtoMessage() {} func (x *Rows) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[8] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -452,7 +532,7 @@ func (x *Rows) ProtoReflect() protoreflect.Message { // Deprecated: Use Rows.ProtoReflect.Descriptor instead. func (*Rows) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{8} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{10} } func (x *Rows) GetConnection() *Connection { @@ -480,7 +560,7 @@ type NextRequest struct { func (x *NextRequest) Reset() { *x = NextRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[9] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -492,7 +572,7 @@ func (x *NextRequest) String() string { func (*NextRequest) ProtoMessage() {} func (x *NextRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[9] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -505,7 +585,7 @@ func (x *NextRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use NextRequest.ProtoReflect.Descriptor instead. func (*NextRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{9} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{11} } func (x *NextRequest) GetRows() *Rows { @@ -541,7 +621,7 @@ type RowData struct { func (x *RowData) Reset() { *x = RowData{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[10] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -553,7 +633,7 @@ func (x *RowData) String() string { func (*RowData) ProtoMessage() {} func (x *RowData) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[10] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -566,7 +646,7 @@ func (x *RowData) ProtoReflect() protoreflect.Message { // Deprecated: Use RowData.ProtoReflect.Descriptor instead. func (*RowData) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{10} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{12} } func (x *RowData) GetRows() *Rows { @@ -606,7 +686,7 @@ type MetadataRequest struct { func (x *MetadataRequest) Reset() { *x = MetadataRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[11] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -618,7 +698,7 @@ func (x *MetadataRequest) String() string { func (*MetadataRequest) ProtoMessage() {} func (x *MetadataRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[11] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -631,7 +711,7 @@ func (x *MetadataRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MetadataRequest.ProtoReflect.Descriptor instead. func (*MetadataRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{11} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{13} } func (x *MetadataRequest) GetRows() *Rows { @@ -650,7 +730,7 @@ type ResultSetStatsRequest struct { func (x *ResultSetStatsRequest) Reset() { *x = ResultSetStatsRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[12] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -662,7 +742,7 @@ func (x *ResultSetStatsRequest) String() string { func (*ResultSetStatsRequest) ProtoMessage() {} func (x *ResultSetStatsRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[12] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -675,7 +755,7 @@ func (x *ResultSetStatsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResultSetStatsRequest.ProtoReflect.Descriptor instead. func (*ResultSetStatsRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{12} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{14} } func (x *ResultSetStatsRequest) GetRows() *Rows { @@ -697,7 +777,7 @@ type ConnectionStreamRequest struct { func (x *ConnectionStreamRequest) Reset() { *x = ConnectionStreamRequest{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[13] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -709,7 +789,7 @@ func (x *ConnectionStreamRequest) String() string { func (*ConnectionStreamRequest) ProtoMessage() {} func (x *ConnectionStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[13] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -722,7 +802,7 @@ func (x *ConnectionStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectionStreamRequest.ProtoReflect.Descriptor instead. func (*ConnectionStreamRequest) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{13} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{15} } func (x *ConnectionStreamRequest) GetRequest() isConnectionStreamRequest_Request { @@ -763,7 +843,7 @@ type ConnectionStreamResponse struct { func (x *ConnectionStreamResponse) Reset() { *x = ConnectionStreamResponse{} - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[14] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -775,7 +855,7 @@ func (x *ConnectionStreamResponse) String() string { func (*ConnectionStreamResponse) ProtoMessage() {} func (x *ConnectionStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[14] + mi := &file_google_spannerlib_v1_spannerlib_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -788,7 +868,7 @@ func (x *ConnectionStreamResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectionStreamResponse.ProtoReflect.Descriptor instead. func (*ConnectionStreamResponse) Descriptor() ([]byte, []int) { - return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{14} + return file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP(), []int{16} } func (x *ConnectionStreamResponse) GetResponse() isConnectionStreamResponse_Response { @@ -821,7 +901,10 @@ var File_google_spannerlib_v1_spannerlib_proto protoreflect.FileDescriptor const file_google_spannerlib_v1_spannerlib_proto_rawDesc = "" + "\n" + - "%google/spannerlib/v1/spannerlib.proto\x12\x14google.spannerlib.v1\x1a\x1fgoogle/api/field_behavior.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\"google/spanner/v1/result_set.proto\x1a\x1fgoogle/spanner/v1/spanner.proto\x1a#google/spanner/v1/transaction.proto\"E\n" + + "%google/spannerlib/v1/spannerlib.proto\x12\x14google.spannerlib.v1\x1a\x1fgoogle/api/field_behavior.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\"google/spanner/v1/result_set.proto\x1a\x1fgoogle/spanner/v1/spanner.proto\x1a#google/spanner/v1/transaction.proto\"\r\n" + + "\vInfoRequest\"(\n" + + "\fInfoResponse\x12\x18\n" + + "\aversion\x18\x01 \x01(\tR\aversion\"E\n" + "\x11CreatePoolRequest\x120\n" + "\x11connection_string\x18\x01 \x01(\tB\x03\xe0A\x02R\x10connectionString\"N\n" + "\x17CreateConnectionRequest\x123\n" + @@ -876,10 +959,10 @@ const file_google_spannerlib_v1_spannerlib_proto_rawDesc = "" + "\x18ConnectionStreamResponse\x127\n" + "\x03row\x18\x01 \x01(\v2#.google.spanner.v1.PartialResultSetH\x00R\x03rowB\n" + "\n" + - "\bresponse2\xf1\n" + - "\n" + + "\bresponse2\xc2\v\n" + "\n" + - "SpannerLib\x12S\n" + + "SpannerLib\x12O\n" + + "\x04Info\x12!.google.spannerlib.v1.InfoRequest\x1a\".google.spannerlib.v1.InfoResponse\"\x00\x12S\n" + "\n" + "CreatePool\x12'.google.spannerlib.v1.CreatePoolRequest\x1a\x1a.google.spannerlib.v1.Pool\"\x00\x12A\n" + "\tClosePool\x12\x1a.google.spannerlib.v1.Pool\x1a\x16.google.protobuf.Empty\"\x00\x12e\n" + @@ -911,90 +994,94 @@ func file_google_spannerlib_v1_spannerlib_proto_rawDescGZIP() []byte { return file_google_spannerlib_v1_spannerlib_proto_rawDescData } -var file_google_spannerlib_v1_spannerlib_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_google_spannerlib_v1_spannerlib_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_google_spannerlib_v1_spannerlib_proto_goTypes = []any{ - (*CreatePoolRequest)(nil), // 0: google.spannerlib.v1.CreatePoolRequest - (*CreateConnectionRequest)(nil), // 1: google.spannerlib.v1.CreateConnectionRequest - (*ExecuteRequest)(nil), // 2: google.spannerlib.v1.ExecuteRequest - (*ExecuteBatchRequest)(nil), // 3: google.spannerlib.v1.ExecuteBatchRequest - (*BeginTransactionRequest)(nil), // 4: google.spannerlib.v1.BeginTransactionRequest - (*WriteMutationsRequest)(nil), // 5: google.spannerlib.v1.WriteMutationsRequest - (*Pool)(nil), // 6: google.spannerlib.v1.Pool - (*Connection)(nil), // 7: google.spannerlib.v1.Connection - (*Rows)(nil), // 8: google.spannerlib.v1.Rows - (*NextRequest)(nil), // 9: google.spannerlib.v1.NextRequest - (*RowData)(nil), // 10: google.spannerlib.v1.RowData - (*MetadataRequest)(nil), // 11: google.spannerlib.v1.MetadataRequest - (*ResultSetStatsRequest)(nil), // 12: google.spannerlib.v1.ResultSetStatsRequest - (*ConnectionStreamRequest)(nil), // 13: google.spannerlib.v1.ConnectionStreamRequest - (*ConnectionStreamResponse)(nil), // 14: google.spannerlib.v1.ConnectionStreamResponse - (*spannerpb.ExecuteSqlRequest)(nil), // 15: google.spanner.v1.ExecuteSqlRequest - (*spannerpb.ExecuteBatchDmlRequest)(nil), // 16: google.spanner.v1.ExecuteBatchDmlRequest - (*spannerpb.TransactionOptions)(nil), // 17: google.spanner.v1.TransactionOptions - (*spannerpb.BatchWriteRequest_MutationGroup)(nil), // 18: google.spanner.v1.BatchWriteRequest.MutationGroup - (*spannerpb.ResultSetMetadata)(nil), // 19: google.spanner.v1.ResultSetMetadata - (*structpb.ListValue)(nil), // 20: google.protobuf.ListValue - (*spannerpb.ResultSetStats)(nil), // 21: google.spanner.v1.ResultSetStats - (*spannerpb.PartialResultSet)(nil), // 22: google.spanner.v1.PartialResultSet - (*emptypb.Empty)(nil), // 23: google.protobuf.Empty - (*spannerpb.ExecuteBatchDmlResponse)(nil), // 24: google.spanner.v1.ExecuteBatchDmlResponse - (*spannerpb.CommitResponse)(nil), // 25: google.spanner.v1.CommitResponse + (*InfoRequest)(nil), // 0: google.spannerlib.v1.InfoRequest + (*InfoResponse)(nil), // 1: google.spannerlib.v1.InfoResponse + (*CreatePoolRequest)(nil), // 2: google.spannerlib.v1.CreatePoolRequest + (*CreateConnectionRequest)(nil), // 3: google.spannerlib.v1.CreateConnectionRequest + (*ExecuteRequest)(nil), // 4: google.spannerlib.v1.ExecuteRequest + (*ExecuteBatchRequest)(nil), // 5: google.spannerlib.v1.ExecuteBatchRequest + (*BeginTransactionRequest)(nil), // 6: google.spannerlib.v1.BeginTransactionRequest + (*WriteMutationsRequest)(nil), // 7: google.spannerlib.v1.WriteMutationsRequest + (*Pool)(nil), // 8: google.spannerlib.v1.Pool + (*Connection)(nil), // 9: google.spannerlib.v1.Connection + (*Rows)(nil), // 10: google.spannerlib.v1.Rows + (*NextRequest)(nil), // 11: google.spannerlib.v1.NextRequest + (*RowData)(nil), // 12: google.spannerlib.v1.RowData + (*MetadataRequest)(nil), // 13: google.spannerlib.v1.MetadataRequest + (*ResultSetStatsRequest)(nil), // 14: google.spannerlib.v1.ResultSetStatsRequest + (*ConnectionStreamRequest)(nil), // 15: google.spannerlib.v1.ConnectionStreamRequest + (*ConnectionStreamResponse)(nil), // 16: google.spannerlib.v1.ConnectionStreamResponse + (*spannerpb.ExecuteSqlRequest)(nil), // 17: google.spanner.v1.ExecuteSqlRequest + (*spannerpb.ExecuteBatchDmlRequest)(nil), // 18: google.spanner.v1.ExecuteBatchDmlRequest + (*spannerpb.TransactionOptions)(nil), // 19: google.spanner.v1.TransactionOptions + (*spannerpb.BatchWriteRequest_MutationGroup)(nil), // 20: google.spanner.v1.BatchWriteRequest.MutationGroup + (*spannerpb.ResultSetMetadata)(nil), // 21: google.spanner.v1.ResultSetMetadata + (*structpb.ListValue)(nil), // 22: google.protobuf.ListValue + (*spannerpb.ResultSetStats)(nil), // 23: google.spanner.v1.ResultSetStats + (*spannerpb.PartialResultSet)(nil), // 24: google.spanner.v1.PartialResultSet + (*emptypb.Empty)(nil), // 25: google.protobuf.Empty + (*spannerpb.ExecuteBatchDmlResponse)(nil), // 26: google.spanner.v1.ExecuteBatchDmlResponse + (*spannerpb.CommitResponse)(nil), // 27: google.spanner.v1.CommitResponse } var file_google_spannerlib_v1_spannerlib_proto_depIdxs = []int32{ - 6, // 0: google.spannerlib.v1.CreateConnectionRequest.pool:type_name -> google.spannerlib.v1.Pool - 7, // 1: google.spannerlib.v1.ExecuteRequest.connection:type_name -> google.spannerlib.v1.Connection - 15, // 2: google.spannerlib.v1.ExecuteRequest.execute_sql_request:type_name -> google.spanner.v1.ExecuteSqlRequest - 7, // 3: google.spannerlib.v1.ExecuteBatchRequest.connection:type_name -> google.spannerlib.v1.Connection - 16, // 4: google.spannerlib.v1.ExecuteBatchRequest.execute_batch_dml_request:type_name -> google.spanner.v1.ExecuteBatchDmlRequest - 7, // 5: google.spannerlib.v1.BeginTransactionRequest.connection:type_name -> google.spannerlib.v1.Connection - 17, // 6: google.spannerlib.v1.BeginTransactionRequest.transaction_options:type_name -> google.spanner.v1.TransactionOptions - 7, // 7: google.spannerlib.v1.WriteMutationsRequest.connection:type_name -> google.spannerlib.v1.Connection - 18, // 8: google.spannerlib.v1.WriteMutationsRequest.mutations:type_name -> google.spanner.v1.BatchWriteRequest.MutationGroup - 6, // 9: google.spannerlib.v1.Connection.pool:type_name -> google.spannerlib.v1.Pool - 7, // 10: google.spannerlib.v1.Rows.connection:type_name -> google.spannerlib.v1.Connection - 8, // 11: google.spannerlib.v1.NextRequest.rows:type_name -> google.spannerlib.v1.Rows - 8, // 12: google.spannerlib.v1.RowData.rows:type_name -> google.spannerlib.v1.Rows - 19, // 13: google.spannerlib.v1.RowData.metadata:type_name -> google.spanner.v1.ResultSetMetadata - 20, // 14: google.spannerlib.v1.RowData.data:type_name -> google.protobuf.ListValue - 21, // 15: google.spannerlib.v1.RowData.stats:type_name -> google.spanner.v1.ResultSetStats - 8, // 16: google.spannerlib.v1.MetadataRequest.rows:type_name -> google.spannerlib.v1.Rows - 8, // 17: google.spannerlib.v1.ResultSetStatsRequest.rows:type_name -> google.spannerlib.v1.Rows - 2, // 18: google.spannerlib.v1.ConnectionStreamRequest.execute_request:type_name -> google.spannerlib.v1.ExecuteRequest - 22, // 19: google.spannerlib.v1.ConnectionStreamResponse.row:type_name -> google.spanner.v1.PartialResultSet - 0, // 20: google.spannerlib.v1.SpannerLib.CreatePool:input_type -> google.spannerlib.v1.CreatePoolRequest - 6, // 21: google.spannerlib.v1.SpannerLib.ClosePool:input_type -> google.spannerlib.v1.Pool - 1, // 22: google.spannerlib.v1.SpannerLib.CreateConnection:input_type -> google.spannerlib.v1.CreateConnectionRequest - 7, // 23: google.spannerlib.v1.SpannerLib.CloseConnection:input_type -> google.spannerlib.v1.Connection - 2, // 24: google.spannerlib.v1.SpannerLib.Execute:input_type -> google.spannerlib.v1.ExecuteRequest - 2, // 25: google.spannerlib.v1.SpannerLib.ExecuteStreaming:input_type -> google.spannerlib.v1.ExecuteRequest - 3, // 26: google.spannerlib.v1.SpannerLib.ExecuteBatch:input_type -> google.spannerlib.v1.ExecuteBatchRequest - 8, // 27: google.spannerlib.v1.SpannerLib.Metadata:input_type -> google.spannerlib.v1.Rows - 9, // 28: google.spannerlib.v1.SpannerLib.Next:input_type -> google.spannerlib.v1.NextRequest - 8, // 29: google.spannerlib.v1.SpannerLib.ResultSetStats:input_type -> google.spannerlib.v1.Rows - 8, // 30: google.spannerlib.v1.SpannerLib.CloseRows:input_type -> google.spannerlib.v1.Rows - 4, // 31: google.spannerlib.v1.SpannerLib.BeginTransaction:input_type -> google.spannerlib.v1.BeginTransactionRequest - 7, // 32: google.spannerlib.v1.SpannerLib.Commit:input_type -> google.spannerlib.v1.Connection - 7, // 33: google.spannerlib.v1.SpannerLib.Rollback:input_type -> google.spannerlib.v1.Connection - 5, // 34: google.spannerlib.v1.SpannerLib.WriteMutations:input_type -> google.spannerlib.v1.WriteMutationsRequest - 13, // 35: google.spannerlib.v1.SpannerLib.ConnectionStream:input_type -> google.spannerlib.v1.ConnectionStreamRequest - 6, // 36: google.spannerlib.v1.SpannerLib.CreatePool:output_type -> google.spannerlib.v1.Pool - 23, // 37: google.spannerlib.v1.SpannerLib.ClosePool:output_type -> google.protobuf.Empty - 7, // 38: google.spannerlib.v1.SpannerLib.CreateConnection:output_type -> google.spannerlib.v1.Connection - 23, // 39: google.spannerlib.v1.SpannerLib.CloseConnection:output_type -> google.protobuf.Empty - 8, // 40: google.spannerlib.v1.SpannerLib.Execute:output_type -> google.spannerlib.v1.Rows - 10, // 41: google.spannerlib.v1.SpannerLib.ExecuteStreaming:output_type -> google.spannerlib.v1.RowData - 24, // 42: google.spannerlib.v1.SpannerLib.ExecuteBatch:output_type -> google.spanner.v1.ExecuteBatchDmlResponse - 19, // 43: google.spannerlib.v1.SpannerLib.Metadata:output_type -> google.spanner.v1.ResultSetMetadata - 20, // 44: google.spannerlib.v1.SpannerLib.Next:output_type -> google.protobuf.ListValue - 21, // 45: google.spannerlib.v1.SpannerLib.ResultSetStats:output_type -> google.spanner.v1.ResultSetStats - 23, // 46: google.spannerlib.v1.SpannerLib.CloseRows:output_type -> google.protobuf.Empty - 23, // 47: google.spannerlib.v1.SpannerLib.BeginTransaction:output_type -> google.protobuf.Empty - 25, // 48: google.spannerlib.v1.SpannerLib.Commit:output_type -> google.spanner.v1.CommitResponse - 23, // 49: google.spannerlib.v1.SpannerLib.Rollback:output_type -> google.protobuf.Empty - 25, // 50: google.spannerlib.v1.SpannerLib.WriteMutations:output_type -> google.spanner.v1.CommitResponse - 14, // 51: google.spannerlib.v1.SpannerLib.ConnectionStream:output_type -> google.spannerlib.v1.ConnectionStreamResponse - 36, // [36:52] is the sub-list for method output_type - 20, // [20:36] is the sub-list for method input_type + 8, // 0: google.spannerlib.v1.CreateConnectionRequest.pool:type_name -> google.spannerlib.v1.Pool + 9, // 1: google.spannerlib.v1.ExecuteRequest.connection:type_name -> google.spannerlib.v1.Connection + 17, // 2: google.spannerlib.v1.ExecuteRequest.execute_sql_request:type_name -> google.spanner.v1.ExecuteSqlRequest + 9, // 3: google.spannerlib.v1.ExecuteBatchRequest.connection:type_name -> google.spannerlib.v1.Connection + 18, // 4: google.spannerlib.v1.ExecuteBatchRequest.execute_batch_dml_request:type_name -> google.spanner.v1.ExecuteBatchDmlRequest + 9, // 5: google.spannerlib.v1.BeginTransactionRequest.connection:type_name -> google.spannerlib.v1.Connection + 19, // 6: google.spannerlib.v1.BeginTransactionRequest.transaction_options:type_name -> google.spanner.v1.TransactionOptions + 9, // 7: google.spannerlib.v1.WriteMutationsRequest.connection:type_name -> google.spannerlib.v1.Connection + 20, // 8: google.spannerlib.v1.WriteMutationsRequest.mutations:type_name -> google.spanner.v1.BatchWriteRequest.MutationGroup + 8, // 9: google.spannerlib.v1.Connection.pool:type_name -> google.spannerlib.v1.Pool + 9, // 10: google.spannerlib.v1.Rows.connection:type_name -> google.spannerlib.v1.Connection + 10, // 11: google.spannerlib.v1.NextRequest.rows:type_name -> google.spannerlib.v1.Rows + 10, // 12: google.spannerlib.v1.RowData.rows:type_name -> google.spannerlib.v1.Rows + 21, // 13: google.spannerlib.v1.RowData.metadata:type_name -> google.spanner.v1.ResultSetMetadata + 22, // 14: google.spannerlib.v1.RowData.data:type_name -> google.protobuf.ListValue + 23, // 15: google.spannerlib.v1.RowData.stats:type_name -> google.spanner.v1.ResultSetStats + 10, // 16: google.spannerlib.v1.MetadataRequest.rows:type_name -> google.spannerlib.v1.Rows + 10, // 17: google.spannerlib.v1.ResultSetStatsRequest.rows:type_name -> google.spannerlib.v1.Rows + 4, // 18: google.spannerlib.v1.ConnectionStreamRequest.execute_request:type_name -> google.spannerlib.v1.ExecuteRequest + 24, // 19: google.spannerlib.v1.ConnectionStreamResponse.row:type_name -> google.spanner.v1.PartialResultSet + 0, // 20: google.spannerlib.v1.SpannerLib.Info:input_type -> google.spannerlib.v1.InfoRequest + 2, // 21: google.spannerlib.v1.SpannerLib.CreatePool:input_type -> google.spannerlib.v1.CreatePoolRequest + 8, // 22: google.spannerlib.v1.SpannerLib.ClosePool:input_type -> google.spannerlib.v1.Pool + 3, // 23: google.spannerlib.v1.SpannerLib.CreateConnection:input_type -> google.spannerlib.v1.CreateConnectionRequest + 9, // 24: google.spannerlib.v1.SpannerLib.CloseConnection:input_type -> google.spannerlib.v1.Connection + 4, // 25: google.spannerlib.v1.SpannerLib.Execute:input_type -> google.spannerlib.v1.ExecuteRequest + 4, // 26: google.spannerlib.v1.SpannerLib.ExecuteStreaming:input_type -> google.spannerlib.v1.ExecuteRequest + 5, // 27: google.spannerlib.v1.SpannerLib.ExecuteBatch:input_type -> google.spannerlib.v1.ExecuteBatchRequest + 10, // 28: google.spannerlib.v1.SpannerLib.Metadata:input_type -> google.spannerlib.v1.Rows + 11, // 29: google.spannerlib.v1.SpannerLib.Next:input_type -> google.spannerlib.v1.NextRequest + 10, // 30: google.spannerlib.v1.SpannerLib.ResultSetStats:input_type -> google.spannerlib.v1.Rows + 10, // 31: google.spannerlib.v1.SpannerLib.CloseRows:input_type -> google.spannerlib.v1.Rows + 6, // 32: google.spannerlib.v1.SpannerLib.BeginTransaction:input_type -> google.spannerlib.v1.BeginTransactionRequest + 9, // 33: google.spannerlib.v1.SpannerLib.Commit:input_type -> google.spannerlib.v1.Connection + 9, // 34: google.spannerlib.v1.SpannerLib.Rollback:input_type -> google.spannerlib.v1.Connection + 7, // 35: google.spannerlib.v1.SpannerLib.WriteMutations:input_type -> google.spannerlib.v1.WriteMutationsRequest + 15, // 36: google.spannerlib.v1.SpannerLib.ConnectionStream:input_type -> google.spannerlib.v1.ConnectionStreamRequest + 1, // 37: google.spannerlib.v1.SpannerLib.Info:output_type -> google.spannerlib.v1.InfoResponse + 8, // 38: google.spannerlib.v1.SpannerLib.CreatePool:output_type -> google.spannerlib.v1.Pool + 25, // 39: google.spannerlib.v1.SpannerLib.ClosePool:output_type -> google.protobuf.Empty + 9, // 40: google.spannerlib.v1.SpannerLib.CreateConnection:output_type -> google.spannerlib.v1.Connection + 25, // 41: google.spannerlib.v1.SpannerLib.CloseConnection:output_type -> google.protobuf.Empty + 10, // 42: google.spannerlib.v1.SpannerLib.Execute:output_type -> google.spannerlib.v1.Rows + 12, // 43: google.spannerlib.v1.SpannerLib.ExecuteStreaming:output_type -> google.spannerlib.v1.RowData + 26, // 44: google.spannerlib.v1.SpannerLib.ExecuteBatch:output_type -> google.spanner.v1.ExecuteBatchDmlResponse + 21, // 45: google.spannerlib.v1.SpannerLib.Metadata:output_type -> google.spanner.v1.ResultSetMetadata + 22, // 46: google.spannerlib.v1.SpannerLib.Next:output_type -> google.protobuf.ListValue + 23, // 47: google.spannerlib.v1.SpannerLib.ResultSetStats:output_type -> google.spanner.v1.ResultSetStats + 25, // 48: google.spannerlib.v1.SpannerLib.CloseRows:output_type -> google.protobuf.Empty + 25, // 49: google.spannerlib.v1.SpannerLib.BeginTransaction:output_type -> google.protobuf.Empty + 27, // 50: google.spannerlib.v1.SpannerLib.Commit:output_type -> google.spanner.v1.CommitResponse + 25, // 51: google.spannerlib.v1.SpannerLib.Rollback:output_type -> google.protobuf.Empty + 27, // 52: google.spannerlib.v1.SpannerLib.WriteMutations:output_type -> google.spanner.v1.CommitResponse + 16, // 53: google.spannerlib.v1.SpannerLib.ConnectionStream:output_type -> google.spannerlib.v1.ConnectionStreamResponse + 37, // [37:54] is the sub-list for method output_type + 20, // [20:37] is the sub-list for method input_type 20, // [20:20] is the sub-list for extension type_name 20, // [20:20] is the sub-list for extension extendee 0, // [0:20] is the sub-list for field type_name @@ -1005,10 +1092,10 @@ func file_google_spannerlib_v1_spannerlib_proto_init() { if File_google_spannerlib_v1_spannerlib_proto != nil { return } - file_google_spannerlib_v1_spannerlib_proto_msgTypes[13].OneofWrappers = []any{ + file_google_spannerlib_v1_spannerlib_proto_msgTypes[15].OneofWrappers = []any{ (*ConnectionStreamRequest_ExecuteRequest)(nil), } - file_google_spannerlib_v1_spannerlib_proto_msgTypes[14].OneofWrappers = []any{ + file_google_spannerlib_v1_spannerlib_proto_msgTypes[16].OneofWrappers = []any{ (*ConnectionStreamResponse_Row)(nil), } type x struct{} @@ -1017,7 +1104,7 @@ func file_google_spannerlib_v1_spannerlib_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_google_spannerlib_v1_spannerlib_proto_rawDesc), len(file_google_spannerlib_v1_spannerlib_proto_rawDesc)), NumEnums: 0, - NumMessages: 15, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.proto b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.proto index 22d6e680..57d58b41 100644 --- a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.proto +++ b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib.proto @@ -18,6 +18,8 @@ option php_namespace = "Google\\Cloud\\SpannerLib\\V1"; option ruby_package = "Google::Cloud::SpannerLib::V1"; service SpannerLib { + rpc Info(InfoRequest) returns (InfoResponse) {} + rpc CreatePool(CreatePoolRequest) returns (Pool) {} rpc ClosePool(Pool) returns (google.protobuf.Empty) {} @@ -41,6 +43,13 @@ service SpannerLib { rpc ConnectionStream(stream ConnectionStreamRequest) returns (stream ConnectionStreamResponse) {} } +message InfoRequest { +} + +message InfoResponse { + string version = 1; +} + message CreatePoolRequest { string connection_string = 1 [ (google.api.field_behavior) = REQUIRED diff --git a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib_grpc.pb.go b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib_grpc.pb.go index a0f8c2bd..b52dd75c 100644 --- a/spannerlib/grpc-server/google/spannerlib/v1/spannerlib_grpc.pb.go +++ b/spannerlib/grpc-server/google/spannerlib/v1/spannerlib_grpc.pb.go @@ -22,6 +22,7 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( + SpannerLib_Info_FullMethodName = "/google.spannerlib.v1.SpannerLib/Info" SpannerLib_CreatePool_FullMethodName = "/google.spannerlib.v1.SpannerLib/CreatePool" SpannerLib_ClosePool_FullMethodName = "/google.spannerlib.v1.SpannerLib/ClosePool" SpannerLib_CreateConnection_FullMethodName = "/google.spannerlib.v1.SpannerLib/CreateConnection" @@ -44,6 +45,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type SpannerLibClient interface { + Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) CreatePool(ctx context.Context, in *CreatePoolRequest, opts ...grpc.CallOption) (*Pool, error) ClosePool(ctx context.Context, in *Pool, opts ...grpc.CallOption) (*emptypb.Empty, error) CreateConnection(ctx context.Context, in *CreateConnectionRequest, opts ...grpc.CallOption) (*Connection, error) @@ -70,6 +72,16 @@ func NewSpannerLibClient(cc grpc.ClientConnInterface) SpannerLibClient { return &spannerLibClient{cc} } +func (c *spannerLibClient) Info(ctx context.Context, in *InfoRequest, opts ...grpc.CallOption) (*InfoResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InfoResponse) + err := c.cc.Invoke(ctx, SpannerLib_Info_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *spannerLibClient) CreatePool(ctx context.Context, in *CreatePoolRequest, opts ...grpc.CallOption) (*Pool, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Pool) @@ -246,6 +258,7 @@ type SpannerLib_ConnectionStreamClient = grpc.BidiStreamingClient[ConnectionStre // All implementations must embed UnimplementedSpannerLibServer // for forward compatibility. type SpannerLibServer interface { + Info(context.Context, *InfoRequest) (*InfoResponse, error) CreatePool(context.Context, *CreatePoolRequest) (*Pool, error) ClosePool(context.Context, *Pool) (*emptypb.Empty, error) CreateConnection(context.Context, *CreateConnectionRequest) (*Connection, error) @@ -272,6 +285,9 @@ type SpannerLibServer interface { // pointer dereference when methods are called. type UnimplementedSpannerLibServer struct{} +func (UnimplementedSpannerLibServer) Info(context.Context, *InfoRequest) (*InfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Info not implemented") +} func (UnimplementedSpannerLibServer) CreatePool(context.Context, *CreatePoolRequest) (*Pool, error) { return nil, status.Errorf(codes.Unimplemented, "method CreatePool not implemented") } @@ -341,6 +357,24 @@ func RegisterSpannerLibServer(s grpc.ServiceRegistrar, srv SpannerLibServer) { s.RegisterService(&SpannerLib_ServiceDesc, srv) } +func _SpannerLib_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SpannerLibServer).Info(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SpannerLib_Info_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SpannerLibServer).Info(ctx, req.(*InfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _SpannerLib_CreatePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreatePoolRequest) if err := dec(in); err != nil { @@ -618,6 +652,10 @@ var SpannerLib_ServiceDesc = grpc.ServiceDesc{ ServiceName: "google.spannerlib.v1.SpannerLib", HandlerType: (*SpannerLibServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "Info", + Handler: _SpannerLib_Info_Handler, + }, { MethodName: "CreatePool", Handler: _SpannerLib_CreatePool_Handler, diff --git a/spannerlib/grpc-server/server.go b/spannerlib/grpc-server/server.go index a16fc758..0235659b 100644 --- a/spannerlib/grpc-server/server.go +++ b/spannerlib/grpc-server/server.go @@ -48,6 +48,10 @@ type spannerLibServer struct { pb.UnimplementedSpannerLibServer } +func (s *spannerLibServer) Info(_ context.Context, _ *pb.InfoRequest) (*pb.InfoResponse, error) { + return &pb.InfoResponse{}, nil +} + func (s *spannerLibServer) CreatePool(ctx context.Context, request *pb.CreatePoolRequest) (*pb.Pool, error) { id, err := api.CreatePool(ctx, request.ConnectionString) if err != nil { diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/GrpcLibSpanner.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/GrpcLibSpanner.cs new file mode 100644 index 00000000..3b65f917 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/GrpcLibSpanner.cs @@ -0,0 +1,403 @@ +// Copyright 2025 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 +// +// https://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. + +using System; +using System.Net.Http; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using Google.Cloud.Spanner.V1; +using Google.Cloud.SpannerLib.V1; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; +using Grpc.Net.Client; +using BeginTransactionRequest = Google.Cloud.SpannerLib.V1.BeginTransactionRequest; +using Status = Google.Rpc.Status; + +namespace Google.Cloud.SpannerLib.Grpc; + +public class GrpcLibSpanner : ISpannerLib +{ + public static GrpcChannel ForUnixSocket(string fileName) + { + var endpoint = new UnixDomainSocketEndPoint(fileName); + return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions { + HttpHandler = new SocketsHttpHandler { + EnableMultipleHttp2Connections = true, + ConnectCallback = async (_, cancellationToken) => { + var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + try { + await socket.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false); + return new NetworkStream(socket, true); + } catch { + socket.Dispose(); + throw; + } + } + } + }); + } + + public static GrpcChannel ForTcpSocket(string address) + { + return GrpcChannel.ForAddress($"http://{address}", new GrpcChannelOptions + { + HttpHandler = new SocketsHttpHandler + { + EnableMultipleHttp2Connections = true, + } + }); + } + + private readonly Server _server; + private readonly V1.SpannerLib.SpannerLibClient _client; + private readonly GrpcChannel _channel; + private readonly V1.SpannerLib.SpannerLibClient[] _clients; + private readonly GrpcChannel[] _channels; + private readonly bool _useStreamingRows; + private bool _disposed; + + public GrpcLibSpanner(bool useStreamingRows = true, Server.AddressType addressType = Server.AddressType.UnixDomainSocket) + { + _server = new Server(); + var file = _server.Start(addressType: addressType); + _channel = addressType == Server.AddressType.Tcp ? ForTcpSocket(file) : ForUnixSocket(file); + _client = new V1.SpannerLib.SpannerLibClient(_channel); + _useStreamingRows = useStreamingRows; + + var numChannels = 1; + _channels = new GrpcChannel[numChannels]; + _clients = new V1.SpannerLib.SpannerLibClient[numChannels]; + for (var i = 0; i < numChannels; i++) + { + _channels[i] = addressType == Server.AddressType.Tcp ? ForTcpSocket(file) : ForUnixSocket(file); + _clients[i] = new V1.SpannerLib.SpannerLibClient(_channels[i]); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + try + { + _channel.Dispose(); + foreach (var channel in _channels) + { + channel.Dispose(); + } + _server.Dispose(); + } + finally + { + _disposed = true; + } + } + + T TranslateException(Func f) + { + try + { + return f.Invoke(); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public Pool CreatePool(string connectionString) + { + return FromProto(TranslateException(() => _client.CreatePool(new CreatePoolRequest + { + ConnectionString = connectionString, + }))); + } + + public void ClosePool(Pool pool) + { + TranslateException(() => _client.ClosePool(ToProto(pool))); + } + + public Connection CreateConnection(Pool pool) + { + return FromProto(pool, TranslateException(() => _client.CreateConnection(new CreateConnectionRequest + { + Pool = ToProto(pool), + }))); + } + + public void CloseConnection(Connection connection) + { + TranslateException(() => _client.CloseConnection(ToProto(connection))); + } + + public async Task CloseConnectionAsync(Connection connection, CancellationToken cancellationToken = default) + { + try + { + await _client.CloseConnectionAsync(ToProto(connection), cancellationToken: cancellationToken); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public CommitResponse? WriteMutations(Connection connection, BatchWriteRequest.Types.MutationGroup mutations) + { + var response = TranslateException(() => _client.WriteMutations(new WriteMutationsRequest + { + Connection = ToProto(connection), + Mutations = mutations, + })); + return response.CommitTimestamp == null ? null : response; + } + + public Rows Execute(Connection connection, ExecuteSqlRequest statement) + { + if (_useStreamingRows) + { + return ExecuteStreaming(connection, statement); + } + return FromProto(connection, TranslateException(() => _client.Execute(new ExecuteRequest + { + Connection = ToProto(connection), + ExecuteSqlRequest = statement, + }))); + } + + private StreamingRows ExecuteStreaming(Connection connection, ExecuteSqlRequest statement) + { + var client = _clients[Random.Shared.Next(_clients.Length)]; + var stream = TranslateException(() => client.ExecuteStreaming(new ExecuteRequest + { + Connection = ToProto(connection), + ExecuteSqlRequest = statement, + })); + return StreamingRows.Create(connection, stream); + } + + public async Task ExecuteAsync(Connection connection, ExecuteSqlRequest statement, CancellationToken cancellationToken = default) + { + try + { + if (_useStreamingRows) + { + return await ExecuteStreamingAsync(connection, statement, cancellationToken); + } + var rows = await _client.ExecuteAsync(new ExecuteRequest + { + Connection = ToProto(connection), + ExecuteSqlRequest = statement, + }, cancellationToken: cancellationToken); + return FromProto(connection, rows); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + private async Task ExecuteStreamingAsync(Connection connection, ExecuteSqlRequest statement, CancellationToken cancellationToken = default) + { + var client = _clients[Random.Shared.Next(_clients.Length)]; + var stream = TranslateException(() => client.ExecuteStreaming(new ExecuteRequest + { + Connection = ToProto(connection), + ExecuteSqlRequest = statement, + })); + return await StreamingRows.CreateAsync(connection, stream, cancellationToken); + } + + public long[] ExecuteBatch(Connection connection, ExecuteBatchDmlRequest statements) + { + var response = TranslateException(() => _client.ExecuteBatch(new ExecuteBatchRequest + { + Connection = ToProto(connection), + ExecuteBatchDmlRequest = statements, + })); + var result = new long[response.ResultSets.Count]; + for (var i = 0; i < result.Length; i++) + { + if (response.ResultSets[i].Stats.HasRowCountExact) + { + result[i] = response.ResultSets[i].Stats.RowCountExact; + } + else if (response.ResultSets[i].Stats.HasRowCountLowerBound) + { + result[i] = response.ResultSets[i].Stats.RowCountLowerBound; + } + else + { + result[i] = -1; + } + } + return result; + } + + public async Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequest statements, CancellationToken cancellationToken = default) + { + try + { + var stats = await _client.ExecuteBatchAsync(new ExecuteBatchRequest + { + Connection = ToProto(connection), + ExecuteBatchDmlRequest = statements, + }, cancellationToken: cancellationToken); + var result = new long[stats.ResultSets.Count]; + for (var i = 0; i < result.Length; i++) + { + result[i] = stats.ResultSets[i].Stats.RowCountExact; + } + return result; + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public ResultSetMetadata? Metadata(Rows rows) + { + return TranslateException(() => _client.Metadata(ToProto(rows))); + } + + public async Task MetadataAsync(Rows rows, CancellationToken cancellationToken = default) + { + try + { + return await _client.MetadataAsync(ToProto(rows), cancellationToken: cancellationToken); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public ResultSetStats? Stats(Rows rows) + { + return TranslateException(() => _client.ResultSetStats(ToProto(rows))); + } + + public ListValue? Next(Rows rows, int numRows, ISpannerLib.RowEncoding encoding) + { + var row = TranslateException(() =>_client.Next(new NextRequest + { + Rows = ToProto(rows), + NumRows = numRows, + Encoding = (long) encoding, + })); + return row.Values.Count == 0 ? null : row; + } + + public async Task NextAsync(Rows rows, int numRows, ISpannerLib.RowEncoding encoding, CancellationToken cancellationToken = default) + { + try + { + return await _client.NextAsync(new NextRequest + { + Rows = ToProto(rows), + NumRows = numRows, + Encoding = (long)encoding, + }, cancellationToken: cancellationToken); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public void CloseRows(Rows rows) + { + TranslateException(() => _client.CloseRows(ToProto(rows))); + } + + public async Task CloseRowsAsync(Rows rows, CancellationToken cancellationToken = default) + { + try + { + await _client.CloseRowsAsync(ToProto(rows), cancellationToken: cancellationToken); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + public void BeginTransaction(Connection connection, TransactionOptions transactionOptions) + { + TranslateException(() => _client.BeginTransaction(new BeginTransactionRequest + { + Connection = ToProto(connection), + TransactionOptions = transactionOptions, + })); + } + + public CommitResponse? Commit(Connection connection) + { + var response = TranslateException(() => _client.Commit(ToProto(connection))); + return response.CommitTimestamp == null ? null : response; + } + + public async Task CommitAsync(Connection connection, CancellationToken cancellationToken = default) + { + try + { + var response = await _client.CommitAsync(ToProto(connection), cancellationToken: cancellationToken); + return response.CommitTimestamp == null ? null : response; + } + catch (RpcException exception) + { + throw new SpannerException(new Status { Code = (int) exception.Status.StatusCode, Message = exception.Status.Detail }); + } + } + + public void Rollback(Connection connection) + { + TranslateException(() => _client.Rollback(ToProto(connection))); + } + + public async Task RollbackAsync(Connection connection, CancellationToken cancellationToken = default) + { + try + { + await _client.RollbackAsync(ToProto(connection), cancellationToken: cancellationToken); + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } + + Pool FromProto(V1.Pool pool) => new(this, pool.Id); + + V1.Pool ToProto(Pool pool) => new() { Id = pool.Id }; + + Connection FromProto(Pool pool, V1.Connection proto) => new(pool, proto.Id); + + V1.Connection ToProto(Connection connection) => new() { Id = connection.Id, Pool = ToProto(connection.Pool), }; + + Rows FromProto(Connection connection, V1.Rows proto) => new(connection, proto.Id); + + V1.Rows ToProto(Rows rows) => new() { Id = rows.Id, Connection = ToProto(rows.SpannerConnection), }; +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/StreamingRows.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/StreamingRows.cs new file mode 100644 index 00000000..1d0c21bf --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/StreamingRows.cs @@ -0,0 +1,131 @@ +using System.Threading; +using System.Threading.Tasks; +using Google.Api.Gax; +using Google.Cloud.Spanner.V1; +using Google.Cloud.SpannerLib.V1; +using Google.Protobuf.WellKnownTypes; +using Grpc.Core; +using Status = Google.Rpc.Status; + +namespace Google.Cloud.SpannerLib.Grpc; + +public class StreamingRows : Rows +{ + private readonly AsyncServerStreamingCall _stream; + private ListValue? _pendingRow; + private ResultSetMetadata? _metadata; + private ResultSetStats? _stats; + private bool _done; + + protected override ResultSetStats? Stats => _stats; + + public override ResultSetMetadata? Metadata => _metadata; + + public static StreamingRows Create(Connection connection, AsyncServerStreamingCall stream) + { + var rows = new StreamingRows(connection, stream); + rows._pendingRow = rows.Next(); + return rows; + } + + public static async Task CreateAsync(Connection connection, AsyncServerStreamingCall stream, CancellationToken cancellationToken = default) + { + var rows = new StreamingRows(connection, stream); + rows._pendingRow = await rows.NextAsync(cancellationToken); + return rows; + } + + private StreamingRows(Connection connection, AsyncServerStreamingCall stream) : base(connection, 0, initMetadata: false) + { + _stream = stream; + } + + protected override void Dispose(bool disposing) + { + if (!_done) + { + MarkDone(); + } + _stream.Dispose(); + base.Dispose(disposing); + } + + private void MarkDone() + { + _done = true; + } + + public override ListValue? Next() + { + if (_pendingRow != null) { + var row = _pendingRow; + _pendingRow = null; + return row; + } + try + { + var hasNext = Task.Run(() => _stream.ResponseStream.MoveNext()).ResultWithUnwrappedExceptions(); + if (!hasNext) + { + MarkDone(); + return null; + } + var rowData = _stream.ResponseStream.Current; + if (rowData.Metadata != null) + { + _metadata = rowData.Metadata; + } + if (rowData.Stats != null) + { + _stats = rowData.Stats; + } + if (rowData.Data.Count == 0) + { + MarkDone(); + return null; + } + return rowData.Data[0]; + } + catch (RpcException exception) + { + throw new SpannerException(new Status { Code = (int) exception.Status.StatusCode, Message = exception.Status.Detail }); + } + } + + public override async Task NextAsync(CancellationToken cancellationToken = default) + { + if (_pendingRow != null) { + var row = _pendingRow; + _pendingRow = null; + return row; + } + try + { + var hasNext = await _stream.ResponseStream.MoveNext(cancellationToken); + if (!hasNext) + { + MarkDone(); + return null; + } + var rowData = _stream.ResponseStream.Current; + if (rowData.Metadata != null) + { + _metadata = rowData.Metadata; + } + if (rowData.Stats != null) + { + _stats = rowData.Stats; + } + if (rowData.Data.Count == 0) + { + MarkDone(); + return null; + } + return rowData.Data[0]; + } + catch (RpcException exception) + { + throw SpannerException.ToSpannerException(exception); + } + } +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/spannerlib-dotnet-grpc-impl.csproj b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/spannerlib-dotnet-grpc-impl.csproj new file mode 100644 index 00000000..d892dd9b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-impl/spannerlib-dotnet-grpc-impl.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Google.Cloud.SpannerLib.Grpc + enable + default + + + + + + + + + + + + diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/Server.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/Server.cs new file mode 100644 index 00000000..1235d086 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/Server.cs @@ -0,0 +1,196 @@ +// Copyright 2025 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 +// +// https://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. + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Google.Cloud.SpannerLib.Grpc; + +public class Server : IDisposable +{ + public enum AddressType + { + UnixDomainSocket, + Tcp, + } + + private Process? _process; + private string? _host; + private bool _disposed; + + public bool IsRunning => _process is { HasExited: false }; + + public Server() + { + } + + public string Start(AddressType addressType = AddressType.UnixDomainSocket) + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(Server)); + } + if (IsRunning) + { + throw new InvalidOperationException("The server is already started."); + } + (_host, _process) = StartGrpcServer(addressType, TimeSpan.FromSeconds(5)); + return _host; + } + + private static Tuple StartGrpcServer(AddressType addressType, TimeSpan timeout) + { + string arguments; + if (addressType == AddressType.UnixDomainSocket) + { + // Generate a random temp file name that will be used for the Unix domain socket communication. + arguments = Path.GetTempPath() + Guid.NewGuid(); + } + else if (addressType == AddressType.Tcp) + { + arguments = "localhost:0 tcp"; + } + else + { + arguments = "localhost:0 tcp"; + } + + var binaryFileName = GetBinaryFileName().Replace('/', Path.DirectorySeparatorChar); + var info = new ProcessStartInfo + { + Arguments = arguments, + UseShellExecute = false, + FileName = binaryFileName, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + // Start the process as a child process. The process will automatically stop when the + // parent process stops. + var process = Process.Start(info); + if (process == null) + { + throw new InvalidOperationException("Failed to start spanner"); + } + if (addressType == AddressType.UnixDomainSocket) + { + var watch = new Stopwatch(); + while (!File.Exists(arguments)) + { + if (watch.Elapsed > timeout) + { + throw new TimeoutException($"Attempt to start gRPC server timed out after {timeout}"); + } + Thread.Sleep(1); + } + } + if (addressType == AddressType.UnixDomainSocket) + { + // Return the name of the Unix domain socket. + return Tuple.Create(arguments, process); + } + // Read the dynamically assigned port. + var address = process.StandardError.ReadLine(); + if (address?.Contains("Starting gRPC server on") ?? false) + { + var lastSpace = address.LastIndexOf(" ", StringComparison.Ordinal); + return Tuple.Create(address.Substring(lastSpace + 1), process); + } + throw new InvalidOperationException("Failed to read gRPC address"); + } + + private static string GetBinaryFileName() + { + string? fileName = null; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + switch (RuntimeInformation.OSArchitecture) + { + case Architecture.X64: + fileName = "runtimes/win-x64/native/grpc_server.exe"; + break; + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + switch (RuntimeInformation.OSArchitecture) + { + case Architecture.X64: + fileName = "runtimes/linux-x64/native/grpc_server"; + break; + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + switch (RuntimeInformation.ProcessArchitecture) + { + case Architecture.Arm64: + fileName = "runtimes/osx-arm64/native/grpc_server"; + break; + } + } + if (fileName != null && File.Exists(fileName)) + { + return fileName; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (File.Exists("runtimes/any/native/grpc_server.exe")) + { + return "runtimes/any/native/grpc_server.exe"; + } + } + if (File.Exists("runtimes/any/native/grpc_server")) + { + return "runtimes/any/native/grpc_server"; + } + + throw new PlatformNotSupportedException(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void Stop() + { + if (_process == null || _process.HasExited) + { + return; + } + _process.Kill(); + _process.WaitForExit(); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + try + { + Stop(); + _process?.Dispose(); + } + finally + { + _disposed = true; + } + } +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/build.sh b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/build.sh new file mode 100755 index 00000000..308e2328 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/build.sh @@ -0,0 +1,16 @@ +# Builds the gRPC server and the binary .NET wrapper and install the latter in a local nuget repository. + +# Determine OS + Arch +export DEST=binaries/any/grpc_server +mkdir -p binaries/any +mkdir -p binaries/osx-arm64 + +# Clear all local nuget cache +dotnet nuget locals --clear all +go build -o ../../../grpc-server/grpc_server ../../../grpc-server/server.go +cp ../../../grpc-server/grpc_server $DEST +cp ../../../grpc-server/grpc_server binaries/osx-arm64/grpc_server +dotnet pack +dotnet nuget remove source local_grpc_server 2>/dev/null +dotnet nuget add source "$PWD"/bin/Release --name local_grpc_server +dotnet restore ../spannerlib-dotnet-grpc-impl diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/spannerlib-dotnet-grpc-server.csproj b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/spannerlib-dotnet-grpc-server.csproj new file mode 100644 index 00000000..644c78f9 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-server/spannerlib-dotnet-grpc-server.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.1 + Google.Cloud.SpannerLib.Grpc + enable + default + Google.Cloud.SpannerLib.GrpcServer + SpannerLib Grpc Server + Google + + + + + + + + + diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/ServerTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/ServerTests.cs new file mode 100644 index 00000000..ff243f47 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/ServerTests.cs @@ -0,0 +1,50 @@ +// Copyright 2025 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 +// +// https://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. + +using Google.Cloud.SpannerLib.V1; + +namespace Google.Cloud.SpannerLib.Grpc; + +public class Tests +{ + private Server _server; + + [SetUp] + public void Setup() + { + _server = new Server(); + } + + [TearDown] + public void TearDown() + { + _server.Dispose(); + } + + [Test] + public void TestStartStop() + { + Assert.That(_server.IsRunning, Is.False); + var file = _server.Start(); + Assert.That(_server.IsRunning, Is.True); + + using var channel = GrpcLibSpanner.ForUnixSocket(file); + var client = new V1.SpannerLib.SpannerLibClient(channel); + var info = client.Info(new InfoRequest()); + Assert.That(info, Is.Not.Null); + + _server.Stop(); + Assert.That(_server.IsRunning, Is.False); + } +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/spannerlib-dotnet-grpc-tests.csproj b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/spannerlib-dotnet-grpc-tests.csproj new file mode 100644 index 00000000..eaca43e4 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-tests/spannerlib-dotnet-grpc-tests.csproj @@ -0,0 +1,28 @@ + + + + net9.0 + Google.Cloud.SpannerLib.Grpc + latest + enable + enable + false + + + + + + + + + + + + + + + + + + + diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/Spannerlib.g.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/Spannerlib.g.cs new file mode 100644 index 00000000..14132a1d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/Spannerlib.g.cs @@ -0,0 +1,4102 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/spannerlib/v1/spannerlib.proto +// +#pragma warning disable 1591, 0612, 3021, 8981 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Google.Cloud.SpannerLib.V1 { + + /// Holder for reflection information generated from google/spannerlib/v1/spannerlib.proto + public static partial class SpannerlibReflection { + + #region Descriptor + /// File descriptor for google/spannerlib/v1/spannerlib.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static SpannerlibReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CiVnb29nbGUvc3Bhbm5lcmxpYi92MS9zcGFubmVybGliLnByb3RvEhRnb29n", + "bGUuc3Bhbm5lcmxpYi52MRofZ29vZ2xlL2FwaS9maWVsZF9iZWhhdmlvci5w", + "cm90bxobZ29vZ2xlL3Byb3RvYnVmL2VtcHR5LnByb3RvGhxnb29nbGUvcHJv", + "dG9idWYvc3RydWN0LnByb3RvGiJnb29nbGUvc3Bhbm5lci92MS9yZXN1bHRf", + "c2V0LnByb3RvGh9nb29nbGUvc3Bhbm5lci92MS9zcGFubmVyLnByb3RvGiNn", + "b29nbGUvc3Bhbm5lci92MS90cmFuc2FjdGlvbi5wcm90byINCgtJbmZvUmVx", + "dWVzdCIfCgxJbmZvUmVzcG9uc2USDwoHdmVyc2lvbhgBIAEoCSIzChFDcmVh", + "dGVQb29sUmVxdWVzdBIeChFjb25uZWN0aW9uX3N0cmluZxgBIAEoCUID4EEC", + "IkgKF0NyZWF0ZUNvbm5lY3Rpb25SZXF1ZXN0Ei0KBHBvb2wYASABKAsyGi5n", + "b29nbGUuc3Bhbm5lcmxpYi52MS5Qb29sQgPgQQIikwEKDkV4ZWN1dGVSZXF1", + "ZXN0EjkKCmNvbm5lY3Rpb24YASABKAsyIC5nb29nbGUuc3Bhbm5lcmxpYi52", + "MS5Db25uZWN0aW9uQgPgQQISRgoTZXhlY3V0ZV9zcWxfcmVxdWVzdBgCIAEo", + "CzIkLmdvb2dsZS5zcGFubmVyLnYxLkV4ZWN1dGVTcWxSZXF1ZXN0QgPgQQIi", + "owEKE0V4ZWN1dGVCYXRjaFJlcXVlc3QSOQoKY29ubmVjdGlvbhgBIAEoCzIg", + "Lmdvb2dsZS5zcGFubmVybGliLnYxLkNvbm5lY3Rpb25CA+BBAhJRChlleGVj", + "dXRlX2JhdGNoX2RtbF9yZXF1ZXN0GAIgASgLMikuZ29vZ2xlLnNwYW5uZXIu", + "djEuRXhlY3V0ZUJhdGNoRG1sUmVxdWVzdEID4EECIp0BChdCZWdpblRyYW5z", + "YWN0aW9uUmVxdWVzdBI5Cgpjb25uZWN0aW9uGAEgASgLMiAuZ29vZ2xlLnNw", + "YW5uZXJsaWIudjEuQ29ubmVjdGlvbkID4EECEkcKE3RyYW5zYWN0aW9uX29w", + "dGlvbnMYAiABKAsyJS5nb29nbGUuc3Bhbm5lci52MS5UcmFuc2FjdGlvbk9w", + "dGlvbnNCA+BBAiKeAQoVV3JpdGVNdXRhdGlvbnNSZXF1ZXN0EjkKCmNvbm5l", + "Y3Rpb24YASABKAsyIC5nb29nbGUuc3Bhbm5lcmxpYi52MS5Db25uZWN0aW9u", + "QgPgQQISSgoJbXV0YXRpb25zGAIgASgLMjIuZ29vZ2xlLnNwYW5uZXIudjEu", + "QmF0Y2hXcml0ZVJlcXVlc3QuTXV0YXRpb25Hcm91cEID4EECIhcKBFBvb2wS", + "DwoCaWQYASABKANCA+BBAiJMCgpDb25uZWN0aW9uEi0KBHBvb2wYASABKAsy", + "Gi5nb29nbGUuc3Bhbm5lcmxpYi52MS5Qb29sQgPgQQISDwoCaWQYAiABKANC", + "A+BBAiJSCgRSb3dzEjkKCmNvbm5lY3Rpb24YASABKAsyIC5nb29nbGUuc3Bh", + "bm5lcmxpYi52MS5Db25uZWN0aW9uQgPgQQISDwoCaWQYAiABKANCA+BBAiJq", + "CgtOZXh0UmVxdWVzdBItCgRyb3dzGAEgASgLMhouZ29vZ2xlLnNwYW5uZXJs", + "aWIudjEuUm93c0ID4EECEhUKCG51bV9yb3dzGAIgASgDQgPgQQISFQoIZW5j", + "b2RpbmcYAyABKANCA+BBAiLRAQoHUm93RGF0YRItCgRyb3dzGAEgASgLMhou", + "Z29vZ2xlLnNwYW5uZXJsaWIudjEuUm93c0ID4EECEjYKCG1ldGFkYXRhGAIg", + "ASgLMiQuZ29vZ2xlLnNwYW5uZXIudjEuUmVzdWx0U2V0TWV0YWRhdGESLQoE", + "ZGF0YRgDIAMoCzIaLmdvb2dsZS5wcm90b2J1Zi5MaXN0VmFsdWVCA+BBAhIw", + "CgVzdGF0cxgEIAEoCzIhLmdvb2dsZS5zcGFubmVyLnYxLlJlc3VsdFNldFN0", + "YXRzIkAKD01ldGFkYXRhUmVxdWVzdBItCgRyb3dzGAEgASgLMhouZ29vZ2xl", + "LnNwYW5uZXJsaWIudjEuUm93c0ID4EECIkYKFVJlc3VsdFNldFN0YXRzUmVx", + "dWVzdBItCgRyb3dzGAEgASgLMhouZ29vZ2xlLnNwYW5uZXJsaWIudjEuUm93", + "c0ID4EECImUKF0Nvbm5lY3Rpb25TdHJlYW1SZXF1ZXN0Ej8KD2V4ZWN1dGVf", + "cmVxdWVzdBgBIAEoCzIkLmdvb2dsZS5zcGFubmVybGliLnYxLkV4ZWN1dGVS", + "ZXF1ZXN0SABCCQoHcmVxdWVzdCJaChhDb25uZWN0aW9uU3RyZWFtUmVzcG9u", + "c2USMgoDcm93GAEgASgLMiMuZ29vZ2xlLnNwYW5uZXIudjEuUGFydGlhbFJl", + "c3VsdFNldEgAQgoKCHJlc3BvbnNlMsILCgpTcGFubmVyTGliEk8KBEluZm8S", + "IS5nb29nbGUuc3Bhbm5lcmxpYi52MS5JbmZvUmVxdWVzdBoiLmdvb2dsZS5z", + "cGFubmVybGliLnYxLkluZm9SZXNwb25zZSIAElMKCkNyZWF0ZVBvb2wSJy5n", + "b29nbGUuc3Bhbm5lcmxpYi52MS5DcmVhdGVQb29sUmVxdWVzdBoaLmdvb2ds", + "ZS5zcGFubmVybGliLnYxLlBvb2wiABJBCglDbG9zZVBvb2wSGi5nb29nbGUu", + "c3Bhbm5lcmxpYi52MS5Qb29sGhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IgAS", + "ZQoQQ3JlYXRlQ29ubmVjdGlvbhItLmdvb2dsZS5zcGFubmVybGliLnYxLkNy", + "ZWF0ZUNvbm5lY3Rpb25SZXF1ZXN0GiAuZ29vZ2xlLnNwYW5uZXJsaWIudjEu", + "Q29ubmVjdGlvbiIAEk0KD0Nsb3NlQ29ubmVjdGlvbhIgLmdvb2dsZS5zcGFu", + "bmVybGliLnYxLkNvbm5lY3Rpb24aFi5nb29nbGUucHJvdG9idWYuRW1wdHki", + "ABJNCgdFeGVjdXRlEiQuZ29vZ2xlLnNwYW5uZXJsaWIudjEuRXhlY3V0ZVJl", + "cXVlc3QaGi5nb29nbGUuc3Bhbm5lcmxpYi52MS5Sb3dzIgASWwoQRXhlY3V0", + "ZVN0cmVhbWluZxIkLmdvb2dsZS5zcGFubmVybGliLnYxLkV4ZWN1dGVSZXF1", + "ZXN0Gh0uZ29vZ2xlLnNwYW5uZXJsaWIudjEuUm93RGF0YSIAMAESZwoMRXhl", + "Y3V0ZUJhdGNoEikuZ29vZ2xlLnNwYW5uZXJsaWIudjEuRXhlY3V0ZUJhdGNo", + "UmVxdWVzdBoqLmdvb2dsZS5zcGFubmVyLnYxLkV4ZWN1dGVCYXRjaERtbFJl", + "c3BvbnNlIgASTgoITWV0YWRhdGESGi5nb29nbGUuc3Bhbm5lcmxpYi52MS5S", + "b3dzGiQuZ29vZ2xlLnNwYW5uZXIudjEuUmVzdWx0U2V0TWV0YWRhdGEiABJH", + "CgROZXh0EiEuZ29vZ2xlLnNwYW5uZXJsaWIudjEuTmV4dFJlcXVlc3QaGi5n", + "b29nbGUucHJvdG9idWYuTGlzdFZhbHVlIgASUQoOUmVzdWx0U2V0U3RhdHMS", + "Gi5nb29nbGUuc3Bhbm5lcmxpYi52MS5Sb3dzGiEuZ29vZ2xlLnNwYW5uZXIu", + "djEuUmVzdWx0U2V0U3RhdHMiABJBCglDbG9zZVJvd3MSGi5nb29nbGUuc3Bh", + "bm5lcmxpYi52MS5Sb3dzGhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IgASWwoQ", + "QmVnaW5UcmFuc2FjdGlvbhItLmdvb2dsZS5zcGFubmVybGliLnYxLkJlZ2lu", + "VHJhbnNhY3Rpb25SZXF1ZXN0GhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5IgAS", + "TwoGQ29tbWl0EiAuZ29vZ2xlLnNwYW5uZXJsaWIudjEuQ29ubmVjdGlvbhoh", + "Lmdvb2dsZS5zcGFubmVyLnYxLkNvbW1pdFJlc3BvbnNlIgASRgoIUm9sbGJh", + "Y2sSIC5nb29nbGUuc3Bhbm5lcmxpYi52MS5Db25uZWN0aW9uGhYuZ29vZ2xl", + "LnByb3RvYnVmLkVtcHR5IgASYgoOV3JpdGVNdXRhdGlvbnMSKy5nb29nbGUu", + "c3Bhbm5lcmxpYi52MS5Xcml0ZU11dGF0aW9uc1JlcXVlc3QaIS5nb29nbGUu", + "c3Bhbm5lci52MS5Db21taXRSZXNwb25zZSIAEncKEENvbm5lY3Rpb25TdHJl", + "YW0SLS5nb29nbGUuc3Bhbm5lcmxpYi52MS5Db25uZWN0aW9uU3RyZWFtUmVx", + "dWVzdBouLmdvb2dsZS5zcGFubmVybGliLnYxLkNvbm5lY3Rpb25TdHJlYW1S", + "ZXNwb25zZSIAKAEwAULNAQoeY29tLmdvb2dsZS5jbG91ZC5zcGFubmVybGli", + "LnYxQg9TcGFubmVyTGliUHJvdG9QAVo+Y2xvdWQuZ29vZ2xlLmNvbS9nby9z", + "cGFubmVybGliL2FwaXYxL3NwYW5uZXJsaWJwYjtzcGFubmVybGlicGKqAhpH", + "b29nbGUuQ2xvdWQuU3Bhbm5lckxpYi5WMcoCGkdvb2dsZVxDbG91ZFxTcGFu", + "bmVyTGliXFYx6gIdR29vZ2xlOjpDbG91ZDo6U3Bhbm5lckxpYjo6VjFiBnBy", + "b3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::Google.Api.FieldBehaviorReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, global::Google.Cloud.Spanner.V1.ResultSetReflection.Descriptor, global::Google.Cloud.Spanner.V1.SpannerReflection.Descriptor, global::Google.Cloud.Spanner.V1.TransactionReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.InfoRequest), global::Google.Cloud.SpannerLib.V1.InfoRequest.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.InfoResponse), global::Google.Cloud.SpannerLib.V1.InfoResponse.Parser, new[]{ "Version" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.CreatePoolRequest), global::Google.Cloud.SpannerLib.V1.CreatePoolRequest.Parser, new[]{ "ConnectionString" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest), global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest.Parser, new[]{ "Pool" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.ExecuteRequest), global::Google.Cloud.SpannerLib.V1.ExecuteRequest.Parser, new[]{ "Connection", "ExecuteSqlRequest" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest), global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest.Parser, new[]{ "Connection", "ExecuteBatchDmlRequest" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest), global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest.Parser, new[]{ "Connection", "TransactionOptions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest), global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest.Parser, new[]{ "Connection", "Mutations" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.Pool), global::Google.Cloud.SpannerLib.V1.Pool.Parser, new[]{ "Id" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.Connection), global::Google.Cloud.SpannerLib.V1.Connection.Parser, new[]{ "Pool", "Id" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.Rows), global::Google.Cloud.SpannerLib.V1.Rows.Parser, new[]{ "Connection", "Id" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.NextRequest), global::Google.Cloud.SpannerLib.V1.NextRequest.Parser, new[]{ "Rows", "NumRows", "Encoding" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.RowData), global::Google.Cloud.SpannerLib.V1.RowData.Parser, new[]{ "Rows", "Metadata", "Data", "Stats" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.MetadataRequest), global::Google.Cloud.SpannerLib.V1.MetadataRequest.Parser, new[]{ "Rows" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.ResultSetStatsRequest), global::Google.Cloud.SpannerLib.V1.ResultSetStatsRequest.Parser, new[]{ "Rows" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.ConnectionStreamRequest), global::Google.Cloud.SpannerLib.V1.ConnectionStreamRequest.Parser, new[]{ "ExecuteRequest" }, new[]{ "Request" }, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Cloud.SpannerLib.V1.ConnectionStreamResponse), global::Google.Cloud.SpannerLib.V1.ConnectionStreamResponse.Parser, new[]{ "Row" }, new[]{ "Response" }, null, null, null) + })); + } + #endregion + + } + #region Messages + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class InfoRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InfoRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoRequest(InfoRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoRequest Clone() { + return new InfoRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as InfoRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(InfoRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(InfoRequest other) { + if (other == null) { + return; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class InfoResponse : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InfoResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoResponse(InfoResponse other) : this() { + version_ = other.version_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public InfoResponse Clone() { + return new InfoResponse(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private string version_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string Version { + get { return version_; } + set { + version_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as InfoResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(InfoResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Version.Length != 0) hash ^= Version.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Version.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Version); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Version.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Version); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Version.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Version); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(InfoResponse other) { + if (other == null) { + return; + } + if (other.Version.Length != 0) { + Version = other.Version; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Version = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + Version = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class CreatePoolRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreatePoolRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreatePoolRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreatePoolRequest(CreatePoolRequest other) : this() { + connectionString_ = other.connectionString_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreatePoolRequest Clone() { + return new CreatePoolRequest(this); + } + + /// Field number for the "connection_string" field. + public const int ConnectionStringFieldNumber = 1; + private string connectionString_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string ConnectionString { + get { return connectionString_; } + set { + connectionString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as CreatePoolRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(CreatePoolRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ConnectionString != other.ConnectionString) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (ConnectionString.Length != 0) hash ^= ConnectionString.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (ConnectionString.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ConnectionString); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (ConnectionString.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ConnectionString); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (ConnectionString.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ConnectionString); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(CreatePoolRequest other) { + if (other == null) { + return; + } + if (other.ConnectionString.Length != 0) { + ConnectionString = other.ConnectionString; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + ConnectionString = input.ReadString(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + ConnectionString = input.ReadString(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class CreateConnectionRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateConnectionRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreateConnectionRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreateConnectionRequest(CreateConnectionRequest other) : this() { + pool_ = other.pool_ != null ? other.pool_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public CreateConnectionRequest Clone() { + return new CreateConnectionRequest(this); + } + + /// Field number for the "pool" field. + public const int PoolFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Pool pool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Pool Pool { + get { return pool_; } + set { + pool_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as CreateConnectionRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(CreateConnectionRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Pool, other.Pool)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (pool_ != null) hash ^= Pool.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (pool_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Pool); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (pool_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Pool); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (pool_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pool); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(CreateConnectionRequest other) { + if (other == null) { + return; + } + if (other.pool_ != null) { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + Pool.MergeFrom(other.Pool); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + input.ReadMessage(Pool); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + input.ReadMessage(Pool); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ExecuteRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ExecuteRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteRequest(ExecuteRequest other) : this() { + connection_ = other.connection_ != null ? other.connection_.Clone() : null; + executeSqlRequest_ = other.executeSqlRequest_ != null ? other.executeSqlRequest_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteRequest Clone() { + return new ExecuteRequest(this); + } + + /// Field number for the "connection" field. + public const int ConnectionFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Connection connection_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Connection Connection { + get { return connection_; } + set { + connection_ = value; + } + } + + /// Field number for the "execute_sql_request" field. + public const int ExecuteSqlRequestFieldNumber = 2; + private global::Google.Cloud.Spanner.V1.ExecuteSqlRequest executeSqlRequest_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.ExecuteSqlRequest ExecuteSqlRequest { + get { return executeSqlRequest_; } + set { + executeSqlRequest_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as ExecuteRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(ExecuteRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Connection, other.Connection)) return false; + if (!object.Equals(ExecuteSqlRequest, other.ExecuteSqlRequest)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (connection_ != null) hash ^= Connection.GetHashCode(); + if (executeSqlRequest_ != null) hash ^= ExecuteSqlRequest.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (executeSqlRequest_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ExecuteSqlRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (executeSqlRequest_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ExecuteSqlRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (connection_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Connection); + } + if (executeSqlRequest_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExecuteSqlRequest); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(ExecuteRequest other) { + if (other == null) { + return; + } + if (other.connection_ != null) { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + Connection.MergeFrom(other.Connection); + } + if (other.executeSqlRequest_ != null) { + if (executeSqlRequest_ == null) { + ExecuteSqlRequest = new global::Google.Cloud.Spanner.V1.ExecuteSqlRequest(); + } + ExecuteSqlRequest.MergeFrom(other.ExecuteSqlRequest); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (executeSqlRequest_ == null) { + ExecuteSqlRequest = new global::Google.Cloud.Spanner.V1.ExecuteSqlRequest(); + } + input.ReadMessage(ExecuteSqlRequest); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (executeSqlRequest_ == null) { + ExecuteSqlRequest = new global::Google.Cloud.Spanner.V1.ExecuteSqlRequest(); + } + input.ReadMessage(ExecuteSqlRequest); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ExecuteBatchRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ExecuteBatchRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteBatchRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteBatchRequest(ExecuteBatchRequest other) : this() { + connection_ = other.connection_ != null ? other.connection_.Clone() : null; + executeBatchDmlRequest_ = other.executeBatchDmlRequest_ != null ? other.executeBatchDmlRequest_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ExecuteBatchRequest Clone() { + return new ExecuteBatchRequest(this); + } + + /// Field number for the "connection" field. + public const int ConnectionFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Connection connection_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Connection Connection { + get { return connection_; } + set { + connection_ = value; + } + } + + /// Field number for the "execute_batch_dml_request" field. + public const int ExecuteBatchDmlRequestFieldNumber = 2; + private global::Google.Cloud.Spanner.V1.ExecuteBatchDmlRequest executeBatchDmlRequest_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.ExecuteBatchDmlRequest ExecuteBatchDmlRequest { + get { return executeBatchDmlRequest_; } + set { + executeBatchDmlRequest_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as ExecuteBatchRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(ExecuteBatchRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Connection, other.Connection)) return false; + if (!object.Equals(ExecuteBatchDmlRequest, other.ExecuteBatchDmlRequest)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (connection_ != null) hash ^= Connection.GetHashCode(); + if (executeBatchDmlRequest_ != null) hash ^= ExecuteBatchDmlRequest.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (executeBatchDmlRequest_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ExecuteBatchDmlRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (executeBatchDmlRequest_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ExecuteBatchDmlRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (connection_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Connection); + } + if (executeBatchDmlRequest_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExecuteBatchDmlRequest); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(ExecuteBatchRequest other) { + if (other == null) { + return; + } + if (other.connection_ != null) { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + Connection.MergeFrom(other.Connection); + } + if (other.executeBatchDmlRequest_ != null) { + if (executeBatchDmlRequest_ == null) { + ExecuteBatchDmlRequest = new global::Google.Cloud.Spanner.V1.ExecuteBatchDmlRequest(); + } + ExecuteBatchDmlRequest.MergeFrom(other.ExecuteBatchDmlRequest); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (executeBatchDmlRequest_ == null) { + ExecuteBatchDmlRequest = new global::Google.Cloud.Spanner.V1.ExecuteBatchDmlRequest(); + } + input.ReadMessage(ExecuteBatchDmlRequest); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (executeBatchDmlRequest_ == null) { + ExecuteBatchDmlRequest = new global::Google.Cloud.Spanner.V1.ExecuteBatchDmlRequest(); + } + input.ReadMessage(ExecuteBatchDmlRequest); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class BeginTransactionRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BeginTransactionRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public BeginTransactionRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public BeginTransactionRequest(BeginTransactionRequest other) : this() { + connection_ = other.connection_ != null ? other.connection_.Clone() : null; + transactionOptions_ = other.transactionOptions_ != null ? other.transactionOptions_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public BeginTransactionRequest Clone() { + return new BeginTransactionRequest(this); + } + + /// Field number for the "connection" field. + public const int ConnectionFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Connection connection_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Connection Connection { + get { return connection_; } + set { + connection_ = value; + } + } + + /// Field number for the "transaction_options" field. + public const int TransactionOptionsFieldNumber = 2; + private global::Google.Cloud.Spanner.V1.TransactionOptions transactionOptions_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.TransactionOptions TransactionOptions { + get { return transactionOptions_; } + set { + transactionOptions_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as BeginTransactionRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(BeginTransactionRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Connection, other.Connection)) return false; + if (!object.Equals(TransactionOptions, other.TransactionOptions)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (connection_ != null) hash ^= Connection.GetHashCode(); + if (transactionOptions_ != null) hash ^= TransactionOptions.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (transactionOptions_ != null) { + output.WriteRawTag(18); + output.WriteMessage(TransactionOptions); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (transactionOptions_ != null) { + output.WriteRawTag(18); + output.WriteMessage(TransactionOptions); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (connection_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Connection); + } + if (transactionOptions_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TransactionOptions); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(BeginTransactionRequest other) { + if (other == null) { + return; + } + if (other.connection_ != null) { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + Connection.MergeFrom(other.Connection); + } + if (other.transactionOptions_ != null) { + if (transactionOptions_ == null) { + TransactionOptions = new global::Google.Cloud.Spanner.V1.TransactionOptions(); + } + TransactionOptions.MergeFrom(other.TransactionOptions); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (transactionOptions_ == null) { + TransactionOptions = new global::Google.Cloud.Spanner.V1.TransactionOptions(); + } + input.ReadMessage(TransactionOptions); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (transactionOptions_ == null) { + TransactionOptions = new global::Google.Cloud.Spanner.V1.TransactionOptions(); + } + input.ReadMessage(TransactionOptions); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class WriteMutationsRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new WriteMutationsRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WriteMutationsRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WriteMutationsRequest(WriteMutationsRequest other) : this() { + connection_ = other.connection_ != null ? other.connection_.Clone() : null; + mutations_ = other.mutations_ != null ? other.mutations_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WriteMutationsRequest Clone() { + return new WriteMutationsRequest(this); + } + + /// Field number for the "connection" field. + public const int ConnectionFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Connection connection_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Connection Connection { + get { return connection_; } + set { + connection_ = value; + } + } + + /// Field number for the "mutations" field. + public const int MutationsFieldNumber = 2; + private global::Google.Cloud.Spanner.V1.BatchWriteRequest.Types.MutationGroup mutations_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.BatchWriteRequest.Types.MutationGroup Mutations { + get { return mutations_; } + set { + mutations_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as WriteMutationsRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(WriteMutationsRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Connection, other.Connection)) return false; + if (!object.Equals(Mutations, other.Mutations)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (connection_ != null) hash ^= Connection.GetHashCode(); + if (mutations_ != null) hash ^= Mutations.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (mutations_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Mutations); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (mutations_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Mutations); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (connection_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Connection); + } + if (mutations_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Mutations); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(WriteMutationsRequest other) { + if (other == null) { + return; + } + if (other.connection_ != null) { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + Connection.MergeFrom(other.Connection); + } + if (other.mutations_ != null) { + if (mutations_ == null) { + Mutations = new global::Google.Cloud.Spanner.V1.BatchWriteRequest.Types.MutationGroup(); + } + Mutations.MergeFrom(other.Mutations); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (mutations_ == null) { + Mutations = new global::Google.Cloud.Spanner.V1.BatchWriteRequest.Types.MutationGroup(); + } + input.ReadMessage(Mutations); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 18: { + if (mutations_ == null) { + Mutations = new global::Google.Cloud.Spanner.V1.BatchWriteRequest.Types.MutationGroup(); + } + input.ReadMessage(Mutations); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Pool : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Pool()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Pool() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Pool(Pool other) : this() { + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Pool Clone() { + return new Pool(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Pool); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Pool other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (Id != 0L) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (Id != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Pool other) { + if (other == null) { + return; + } + if (other.Id != 0L) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + Id = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Connection : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Connection()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Connection() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Connection(Connection other) : this() { + pool_ = other.pool_ != null ? other.pool_.Clone() : null; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Connection Clone() { + return new Connection(this); + } + + /// Field number for the "pool" field. + public const int PoolFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Pool pool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Pool Pool { + get { return pool_; } + set { + pool_ = value; + } + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 2; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Connection); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Connection other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Pool, other.Pool)) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (pool_ != null) hash ^= Pool.GetHashCode(); + if (Id != 0L) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (pool_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Pool); + } + if (Id != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (pool_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Pool); + } + if (Id != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (pool_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Pool); + } + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Connection other) { + if (other == null) { + return; + } + if (other.pool_ != null) { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + Pool.MergeFrom(other.Pool); + } + if (other.Id != 0L) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + input.ReadMessage(Pool); + break; + } + case 16: { + Id = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (pool_ == null) { + Pool = new global::Google.Cloud.SpannerLib.V1.Pool(); + } + input.ReadMessage(Pool); + break; + } + case 16: { + Id = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class Rows : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Rows()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Rows() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Rows(Rows other) : this() { + connection_ = other.connection_ != null ? other.connection_.Clone() : null; + id_ = other.id_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Rows Clone() { + return new Rows(this); + } + + /// Field number for the "connection" field. + public const int ConnectionFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Connection connection_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Connection Connection { + get { return connection_; } + set { + connection_ = value; + } + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 2; + private long id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Rows); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Rows other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Connection, other.Connection)) return false; + if (Id != other.Id) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (connection_ != null) hash ^= Connection.GetHashCode(); + if (Id != 0L) hash ^= Id.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (Id != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (connection_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Connection); + } + if (Id != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (connection_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Connection); + } + if (Id != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Rows other) { + if (other == null) { + return; + } + if (other.connection_ != null) { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + Connection.MergeFrom(other.Connection); + } + if (other.Id != 0L) { + Id = other.Id; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 16: { + Id = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (connection_ == null) { + Connection = new global::Google.Cloud.SpannerLib.V1.Connection(); + } + input.ReadMessage(Connection); + break; + } + case 16: { + Id = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class NextRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NextRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NextRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NextRequest(NextRequest other) : this() { + rows_ = other.rows_ != null ? other.rows_.Clone() : null; + numRows_ = other.numRows_; + encoding_ = other.encoding_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public NextRequest Clone() { + return new NextRequest(this); + } + + /// Field number for the "rows" field. + public const int RowsFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Rows rows_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Rows Rows { + get { return rows_; } + set { + rows_ = value; + } + } + + /// Field number for the "num_rows" field. + public const int NumRowsFieldNumber = 2; + private long numRows_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long NumRows { + get { return numRows_; } + set { + numRows_ = value; + } + } + + /// Field number for the "encoding" field. + public const int EncodingFieldNumber = 3; + private long encoding_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long Encoding { + get { return encoding_; } + set { + encoding_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as NextRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(NextRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Rows, other.Rows)) return false; + if (NumRows != other.NumRows) return false; + if (Encoding != other.Encoding) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (rows_ != null) hash ^= Rows.GetHashCode(); + if (NumRows != 0L) hash ^= NumRows.GetHashCode(); + if (Encoding != 0L) hash ^= Encoding.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (NumRows != 0L) { + output.WriteRawTag(16); + output.WriteInt64(NumRows); + } + if (Encoding != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Encoding); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (NumRows != 0L) { + output.WriteRawTag(16); + output.WriteInt64(NumRows); + } + if (Encoding != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Encoding); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (rows_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Rows); + } + if (NumRows != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(NumRows); + } + if (Encoding != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Encoding); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(NextRequest other) { + if (other == null) { + return; + } + if (other.rows_ != null) { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + Rows.MergeFrom(other.Rows); + } + if (other.NumRows != 0L) { + NumRows = other.NumRows; + } + if (other.Encoding != 0L) { + Encoding = other.Encoding; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + case 16: { + NumRows = input.ReadInt64(); + break; + } + case 24: { + Encoding = input.ReadInt64(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + case 16: { + NumRows = input.ReadInt64(); + break; + } + case 24: { + Encoding = input.ReadInt64(); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class RowData : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RowData()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public RowData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public RowData(RowData other) : this() { + rows_ = other.rows_ != null ? other.rows_.Clone() : null; + metadata_ = other.metadata_ != null ? other.metadata_.Clone() : null; + data_ = other.data_.Clone(); + stats_ = other.stats_ != null ? other.stats_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public RowData Clone() { + return new RowData(this); + } + + /// Field number for the "rows" field. + public const int RowsFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Rows rows_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Rows Rows { + get { return rows_; } + set { + rows_ = value; + } + } + + /// Field number for the "metadata" field. + public const int MetadataFieldNumber = 2; + private global::Google.Cloud.Spanner.V1.ResultSetMetadata metadata_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.ResultSetMetadata Metadata { + get { return metadata_; } + set { + metadata_ = value; + } + } + + /// Field number for the "data" field. + public const int DataFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_data_codec + = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.ListValue.Parser); + private readonly pbc::RepeatedField data_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField Data { + get { return data_; } + } + + /// Field number for the "stats" field. + public const int StatsFieldNumber = 4; + private global::Google.Cloud.Spanner.V1.ResultSetStats stats_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.ResultSetStats Stats { + get { return stats_; } + set { + stats_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as RowData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(RowData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Rows, other.Rows)) return false; + if (!object.Equals(Metadata, other.Metadata)) return false; + if(!data_.Equals(other.data_)) return false; + if (!object.Equals(Stats, other.Stats)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (rows_ != null) hash ^= Rows.GetHashCode(); + if (metadata_ != null) hash ^= Metadata.GetHashCode(); + hash ^= data_.GetHashCode(); + if (stats_ != null) hash ^= Stats.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (metadata_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Metadata); + } + data_.WriteTo(output, _repeated_data_codec); + if (stats_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Stats); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (metadata_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Metadata); + } + data_.WriteTo(ref output, _repeated_data_codec); + if (stats_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Stats); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (rows_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Rows); + } + if (metadata_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Metadata); + } + size += data_.CalculateSize(_repeated_data_codec); + if (stats_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Stats); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(RowData other) { + if (other == null) { + return; + } + if (other.rows_ != null) { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + Rows.MergeFrom(other.Rows); + } + if (other.metadata_ != null) { + if (metadata_ == null) { + Metadata = new global::Google.Cloud.Spanner.V1.ResultSetMetadata(); + } + Metadata.MergeFrom(other.Metadata); + } + data_.Add(other.data_); + if (other.stats_ != null) { + if (stats_ == null) { + Stats = new global::Google.Cloud.Spanner.V1.ResultSetStats(); + } + Stats.MergeFrom(other.Stats); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + case 18: { + if (metadata_ == null) { + Metadata = new global::Google.Cloud.Spanner.V1.ResultSetMetadata(); + } + input.ReadMessage(Metadata); + break; + } + case 26: { + data_.AddEntriesFrom(input, _repeated_data_codec); + break; + } + case 34: { + if (stats_ == null) { + Stats = new global::Google.Cloud.Spanner.V1.ResultSetStats(); + } + input.ReadMessage(Stats); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + case 18: { + if (metadata_ == null) { + Metadata = new global::Google.Cloud.Spanner.V1.ResultSetMetadata(); + } + input.ReadMessage(Metadata); + break; + } + case 26: { + data_.AddEntriesFrom(ref input, _repeated_data_codec); + break; + } + case 34: { + if (stats_ == null) { + Stats = new global::Google.Cloud.Spanner.V1.ResultSetStats(); + } + input.ReadMessage(Stats); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class MetadataRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MetadataRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public MetadataRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public MetadataRequest(MetadataRequest other) : this() { + rows_ = other.rows_ != null ? other.rows_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public MetadataRequest Clone() { + return new MetadataRequest(this); + } + + /// Field number for the "rows" field. + public const int RowsFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Rows rows_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Rows Rows { + get { return rows_; } + set { + rows_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as MetadataRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(MetadataRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Rows, other.Rows)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (rows_ != null) hash ^= Rows.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (rows_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Rows); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(MetadataRequest other) { + if (other == null) { + return; + } + if (other.rows_ != null) { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + Rows.MergeFrom(other.Rows); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ResultSetStatsRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResultSetStatsRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ResultSetStatsRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ResultSetStatsRequest(ResultSetStatsRequest other) : this() { + rows_ = other.rows_ != null ? other.rows_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ResultSetStatsRequest Clone() { + return new ResultSetStatsRequest(this); + } + + /// Field number for the "rows" field. + public const int RowsFieldNumber = 1; + private global::Google.Cloud.SpannerLib.V1.Rows rows_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.Rows Rows { + get { return rows_; } + set { + rows_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as ResultSetStatsRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(ResultSetStatsRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Rows, other.Rows)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (rows_ != null) hash ^= Rows.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (rows_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Rows); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (rows_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Rows); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(ResultSetStatsRequest other) { + if (other == null) { + return; + } + if (other.rows_ != null) { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + Rows.MergeFrom(other.Rows); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + if (rows_ == null) { + Rows = new global::Google.Cloud.SpannerLib.V1.Rows(); + } + input.ReadMessage(Rows); + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ConnectionStreamRequest : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ConnectionStreamRequest()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamRequest(ConnectionStreamRequest other) : this() { + switch (other.RequestCase) { + case RequestOneofCase.ExecuteRequest: + ExecuteRequest = other.ExecuteRequest.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamRequest Clone() { + return new ConnectionStreamRequest(this); + } + + /// Field number for the "execute_request" field. + public const int ExecuteRequestFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.SpannerLib.V1.ExecuteRequest ExecuteRequest { + get { return requestCase_ == RequestOneofCase.ExecuteRequest ? (global::Google.Cloud.SpannerLib.V1.ExecuteRequest) request_ : null; } + set { + request_ = value; + requestCase_ = value == null ? RequestOneofCase.None : RequestOneofCase.ExecuteRequest; + } + } + + private object request_; + /// Enum of possible cases for the "request" oneof. + public enum RequestOneofCase { + None = 0, + ExecuteRequest = 1, + } + private RequestOneofCase requestCase_ = RequestOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public RequestOneofCase RequestCase { + get { return requestCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearRequest() { + requestCase_ = RequestOneofCase.None; + request_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as ConnectionStreamRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(ConnectionStreamRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(ExecuteRequest, other.ExecuteRequest)) return false; + if (RequestCase != other.RequestCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (requestCase_ == RequestOneofCase.ExecuteRequest) hash ^= ExecuteRequest.GetHashCode(); + hash ^= (int) requestCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (requestCase_ == RequestOneofCase.ExecuteRequest) { + output.WriteRawTag(10); + output.WriteMessage(ExecuteRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (requestCase_ == RequestOneofCase.ExecuteRequest) { + output.WriteRawTag(10); + output.WriteMessage(ExecuteRequest); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (requestCase_ == RequestOneofCase.ExecuteRequest) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExecuteRequest); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(ConnectionStreamRequest other) { + if (other == null) { + return; + } + switch (other.RequestCase) { + case RequestOneofCase.ExecuteRequest: + if (ExecuteRequest == null) { + ExecuteRequest = new global::Google.Cloud.SpannerLib.V1.ExecuteRequest(); + } + ExecuteRequest.MergeFrom(other.ExecuteRequest); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + global::Google.Cloud.SpannerLib.V1.ExecuteRequest subBuilder = new global::Google.Cloud.SpannerLib.V1.ExecuteRequest(); + if (requestCase_ == RequestOneofCase.ExecuteRequest) { + subBuilder.MergeFrom(ExecuteRequest); + } + input.ReadMessage(subBuilder); + ExecuteRequest = subBuilder; + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + global::Google.Cloud.SpannerLib.V1.ExecuteRequest subBuilder = new global::Google.Cloud.SpannerLib.V1.ExecuteRequest(); + if (requestCase_ == RequestOneofCase.ExecuteRequest) { + subBuilder.MergeFrom(ExecuteRequest); + } + input.ReadMessage(subBuilder); + ExecuteRequest = subBuilder; + break; + } + } + } + } + #endif + + } + + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class ConnectionStreamResponse : pb::IMessage + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage + #endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ConnectionStreamResponse()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamResponse(ConnectionStreamResponse other) : this() { + switch (other.ResponseCase) { + case ResponseOneofCase.Row: + Row = other.Row.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ConnectionStreamResponse Clone() { + return new ConnectionStreamResponse(this); + } + + /// Field number for the "row" field. + public const int RowFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Cloud.Spanner.V1.PartialResultSet Row { + get { return responseCase_ == ResponseOneofCase.Row ? (global::Google.Cloud.Spanner.V1.PartialResultSet) response_ : null; } + set { + response_ = value; + responseCase_ = value == null ? ResponseOneofCase.None : ResponseOneofCase.Row; + } + } + + private object response_; + /// Enum of possible cases for the "response" oneof. + public enum ResponseOneofCase { + None = 0, + Row = 1, + } + private ResponseOneofCase responseCase_ = ResponseOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ResponseOneofCase ResponseCase { + get { return responseCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearResponse() { + responseCase_ = ResponseOneofCase.None; + response_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as ConnectionStreamResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(ConnectionStreamResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Row, other.Row)) return false; + if (ResponseCase != other.ResponseCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (responseCase_ == ResponseOneofCase.Row) hash ^= Row.GetHashCode(); + hash ^= (int) responseCase_; + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (responseCase_ == ResponseOneofCase.Row) { + output.WriteRawTag(10); + output.WriteMessage(Row); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (responseCase_ == ResponseOneofCase.Row) { + output.WriteRawTag(10); + output.WriteMessage(Row); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (responseCase_ == ResponseOneofCase.Row) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Row); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(ConnectionStreamResponse other) { + if (other == null) { + return; + } + switch (other.ResponseCase) { + case ResponseOneofCase.Row: + if (Row == null) { + Row = new global::Google.Cloud.Spanner.V1.PartialResultSet(); + } + Row.MergeFrom(other.Row); + break; + } + + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + global::Google.Cloud.Spanner.V1.PartialResultSet subBuilder = new global::Google.Cloud.Spanner.V1.PartialResultSet(); + if (responseCase_ == ResponseOneofCase.Row) { + subBuilder.MergeFrom(Row); + } + input.ReadMessage(subBuilder); + Row = subBuilder; + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: { + global::Google.Cloud.Spanner.V1.PartialResultSet subBuilder = new global::Google.Cloud.Spanner.V1.PartialResultSet(); + if (responseCase_ == ResponseOneofCase.Row) { + subBuilder.MergeFrom(Row); + } + input.ReadMessage(subBuilder); + Row = subBuilder; + break; + } + } + } + } + #endif + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/SpannerlibGrpc.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/SpannerlibGrpc.cs new file mode 100644 index 00000000..d5e9db94 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/SpannerlibGrpc.cs @@ -0,0 +1,590 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/spannerlib/v1/spannerlib.proto +// +#pragma warning disable 0414, 1591, 8981, 0612 +#region Designer generated code + +using grpc = global::Grpc.Core; + +namespace Google.Cloud.SpannerLib.V1 { + public static partial class SpannerLib + { + static readonly string __ServiceName = "google.spannerlib.v1.SpannerLib"; + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context) + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (message is global::Google.Protobuf.IBufferMessage) + { + context.SetPayloadLength(message.CalculateSize()); + global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter()); + context.Complete(); + return; + } + #endif + context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static class __Helper_MessageCache + { + public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (__Helper_MessageCache.IsBufferMessage) + { + return parser.ParseFrom(context.PayloadAsReadOnlySequence()); + } + #endif + return parser.ParseFrom(context.PayloadAsNewBuffer()); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_InfoRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.InfoRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_InfoResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.InfoResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_CreatePoolRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.CreatePoolRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_Pool = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.Pool.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_protobuf_Empty = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Protobuf.WellKnownTypes.Empty.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_CreateConnectionRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_Connection = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.Connection.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_ExecuteRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.ExecuteRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_Rows = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.Rows.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_RowData = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.RowData.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_ExecuteBatchRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spanner_v1_ExecuteBatchDmlResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.Spanner.V1.ExecuteBatchDmlResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spanner_v1_ResultSetMetadata = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.Spanner.V1.ResultSetMetadata.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_NextRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.NextRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_protobuf_ListValue = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Protobuf.WellKnownTypes.ListValue.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spanner_v1_ResultSetStats = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.Spanner.V1.ResultSetStats.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_BeginTransactionRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spanner_v1_CommitResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.Spanner.V1.CommitResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_WriteMutationsRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_ConnectionStreamRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.ConnectionStreamRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_google_spannerlib_v1_ConnectionStreamResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Google.Cloud.SpannerLib.V1.ConnectionStreamResponse.Parser)); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Info = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Info", + __Marshaller_google_spannerlib_v1_InfoRequest, + __Marshaller_google_spannerlib_v1_InfoResponse); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_CreatePool = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CreatePool", + __Marshaller_google_spannerlib_v1_CreatePoolRequest, + __Marshaller_google_spannerlib_v1_Pool); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_ClosePool = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "ClosePool", + __Marshaller_google_spannerlib_v1_Pool, + __Marshaller_google_protobuf_Empty); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_CreateConnection = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CreateConnection", + __Marshaller_google_spannerlib_v1_CreateConnectionRequest, + __Marshaller_google_spannerlib_v1_Connection); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_CloseConnection = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CloseConnection", + __Marshaller_google_spannerlib_v1_Connection, + __Marshaller_google_protobuf_Empty); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Execute = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Execute", + __Marshaller_google_spannerlib_v1_ExecuteRequest, + __Marshaller_google_spannerlib_v1_Rows); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_ExecuteStreaming = new grpc::Method( + grpc::MethodType.ServerStreaming, + __ServiceName, + "ExecuteStreaming", + __Marshaller_google_spannerlib_v1_ExecuteRequest, + __Marshaller_google_spannerlib_v1_RowData); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_ExecuteBatch = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "ExecuteBatch", + __Marshaller_google_spannerlib_v1_ExecuteBatchRequest, + __Marshaller_google_spanner_v1_ExecuteBatchDmlResponse); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Metadata = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Metadata", + __Marshaller_google_spannerlib_v1_Rows, + __Marshaller_google_spanner_v1_ResultSetMetadata); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Next = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Next", + __Marshaller_google_spannerlib_v1_NextRequest, + __Marshaller_google_protobuf_ListValue); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_ResultSetStats = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "ResultSetStats", + __Marshaller_google_spannerlib_v1_Rows, + __Marshaller_google_spanner_v1_ResultSetStats); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_CloseRows = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CloseRows", + __Marshaller_google_spannerlib_v1_Rows, + __Marshaller_google_protobuf_Empty); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_BeginTransaction = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "BeginTransaction", + __Marshaller_google_spannerlib_v1_BeginTransactionRequest, + __Marshaller_google_protobuf_Empty); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Commit = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Commit", + __Marshaller_google_spannerlib_v1_Connection, + __Marshaller_google_spanner_v1_CommitResponse); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_Rollback = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Rollback", + __Marshaller_google_spannerlib_v1_Connection, + __Marshaller_google_protobuf_Empty); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_WriteMutations = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "WriteMutations", + __Marshaller_google_spannerlib_v1_WriteMutationsRequest, + __Marshaller_google_spanner_v1_CommitResponse); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Method __Method_ConnectionStream = new grpc::Method( + grpc::MethodType.DuplexStreaming, + __ServiceName, + "ConnectionStream", + __Marshaller_google_spannerlib_v1_ConnectionStreamRequest, + __Marshaller_google_spannerlib_v1_ConnectionStreamResponse); + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Google.Cloud.SpannerLib.V1.SpannerlibReflection.Descriptor.Services[0]; } + } + + /// Client for SpannerLib + public partial class SpannerLibClient : grpc::ClientBase + { + /// Creates a new client for SpannerLib + /// The channel to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public SpannerLibClient(grpc::ChannelBase channel) : base(channel) + { + } + /// Creates a new client for SpannerLib that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public SpannerLibClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected SpannerLibClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected SpannerLibClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.InfoResponse Info(global::Google.Cloud.SpannerLib.V1.InfoRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Info(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.InfoResponse Info(global::Google.Cloud.SpannerLib.V1.InfoRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Info, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall InfoAsync(global::Google.Cloud.SpannerLib.V1.InfoRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return InfoAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall InfoAsync(global::Google.Cloud.SpannerLib.V1.InfoRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Info, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Pool CreatePool(global::Google.Cloud.SpannerLib.V1.CreatePoolRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreatePool(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Pool CreatePool(global::Google.Cloud.SpannerLib.V1.CreatePoolRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CreatePool, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreatePoolAsync(global::Google.Cloud.SpannerLib.V1.CreatePoolRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreatePoolAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreatePoolAsync(global::Google.Cloud.SpannerLib.V1.CreatePoolRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CreatePool, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty ClosePool(global::Google.Cloud.SpannerLib.V1.Pool request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ClosePool(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty ClosePool(global::Google.Cloud.SpannerLib.V1.Pool request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_ClosePool, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ClosePoolAsync(global::Google.Cloud.SpannerLib.V1.Pool request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ClosePoolAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ClosePoolAsync(global::Google.Cloud.SpannerLib.V1.Pool request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_ClosePool, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Connection CreateConnection(global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreateConnection(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Connection CreateConnection(global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CreateConnection, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreateConnectionAsync(global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreateConnectionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreateConnectionAsync(global::Google.Cloud.SpannerLib.V1.CreateConnectionRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CreateConnection, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty CloseConnection(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CloseConnection(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty CloseConnection(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CloseConnection, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CloseConnectionAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CloseConnectionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CloseConnectionAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CloseConnection, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Rows Execute(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Execute(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.SpannerLib.V1.Rows Execute(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Execute, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ExecuteAsync(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ExecuteAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ExecuteAsync(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Execute, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncServerStreamingCall ExecuteStreaming(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ExecuteStreaming(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncServerStreamingCall ExecuteStreaming(global::Google.Cloud.SpannerLib.V1.ExecuteRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncServerStreamingCall(__Method_ExecuteStreaming, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ExecuteBatchDmlResponse ExecuteBatch(global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ExecuteBatch(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ExecuteBatchDmlResponse ExecuteBatch(global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_ExecuteBatch, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ExecuteBatchAsync(global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ExecuteBatchAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ExecuteBatchAsync(global::Google.Cloud.SpannerLib.V1.ExecuteBatchRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_ExecuteBatch, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ResultSetMetadata Metadata(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Metadata(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ResultSetMetadata Metadata(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Metadata, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall MetadataAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return MetadataAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall MetadataAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Metadata, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.ListValue Next(global::Google.Cloud.SpannerLib.V1.NextRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Next(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.ListValue Next(global::Google.Cloud.SpannerLib.V1.NextRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Next, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall NextAsync(global::Google.Cloud.SpannerLib.V1.NextRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return NextAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall NextAsync(global::Google.Cloud.SpannerLib.V1.NextRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Next, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ResultSetStats ResultSetStats(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ResultSetStats(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.ResultSetStats ResultSetStats(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_ResultSetStats, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ResultSetStatsAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ResultSetStatsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ResultSetStatsAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_ResultSetStats, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty CloseRows(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CloseRows(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty CloseRows(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_CloseRows, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CloseRowsAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CloseRowsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CloseRowsAsync(global::Google.Cloud.SpannerLib.V1.Rows request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_CloseRows, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty BeginTransaction(global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return BeginTransaction(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty BeginTransaction(global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_BeginTransaction, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BeginTransactionAsync(global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return BeginTransactionAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BeginTransactionAsync(global::Google.Cloud.SpannerLib.V1.BeginTransactionRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_BeginTransaction, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.CommitResponse Commit(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Commit(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.CommitResponse Commit(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Commit, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CommitAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CommitAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CommitAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Commit, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty Rollback(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Rollback(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Protobuf.WellKnownTypes.Empty Rollback(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_Rollback, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall RollbackAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return RollbackAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall RollbackAsync(global::Google.Cloud.SpannerLib.V1.Connection request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_Rollback, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.CommitResponse WriteMutations(global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return WriteMutations(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Google.Cloud.Spanner.V1.CommitResponse WriteMutations(global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__Method_WriteMutations, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall WriteMutationsAsync(global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return WriteMutationsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall WriteMutationsAsync(global::Google.Cloud.SpannerLib.V1.WriteMutationsRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__Method_WriteMutations, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall ConnectionStream(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ConnectionStream(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall ConnectionStream(grpc::CallOptions options) + { + return CallInvoker.AsyncDuplexStreamingCall(__Method_ConnectionStream, null, options); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected override SpannerLibClient NewInstance(ClientBaseConfiguration configuration) + { + return new SpannerLibClient(configuration); + } + } + + } +} +#endregion diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/spannerlib-dotnet-grpc-v1.csproj b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/spannerlib-dotnet-grpc-v1.csproj new file mode 100644 index 00000000..3141df11 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/spannerlib-dotnet-grpc-v1.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.1 + Google.Cloud.SpannerLib.V1 + enable + default + + + + + + + + diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/MockSpannerServer.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/MockSpannerServer.cs index 269c77ab..28118fdf 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/MockSpannerServer.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/MockSpannerServer.cs @@ -795,4 +795,10 @@ public override Task DropDatabase(DropDatabaseRequest request, ServerCall _requests.Enqueue(request); return Task.FromResult(new Empty()); } + + public void Reset() + { + _requests.Clear(); + } + } \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/SpannerConverter.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/SpannerConverter.cs index cbb3096c..9b64ffab 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/SpannerConverter.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-mockserver/SpannerConverter.cs @@ -61,10 +61,18 @@ internal static Value ToProtobufValue(Spanner.V1.Type type, object? value) .ToString(InvariantCulture) }; case TypeCode.Float32: + if (value is float float32) + { + return new Value { NumberValue = float32 }; + } return new Value { NumberValue = Convert.ToSingle(value, InvariantCulture) }; case TypeCode.Float64: return new Value { NumberValue = Convert.ToDouble(value, InvariantCulture) }; case TypeCode.Timestamp: + if (value is string value1) + { + return Value.ForString(value1); + } return new Value { StringValue = XmlConvert.ToString(Convert.ToDateTime(value, InvariantCulture), XmlDateTimeSerializationMode.Utc) @@ -100,7 +108,7 @@ internal static Value ToProtobufValue(Spanner.V1.Type type, object? value) } if (value is string str) { - return Value.ForString(SpannerNumeric.Parse(str).ToString()); + return Value.ForString(str); } if (value is float || value is double || value is decimal) { @@ -122,6 +130,8 @@ internal static Value ToProtobufValue(Spanner.V1.Type type, object? value) return Value.ForString(numericValue.ToString()); } throw new ArgumentException("Numeric parameters must be of type SpannerNumeric or string"); + case TypeCode.Uuid: + return Value.ForString(value.ToString()); default: throw new ArgumentOutOfRangeException(nameof(type.Code), type.Code, null); diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-native-impl/SharedLibSpanner.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-native-impl/SharedLibSpanner.cs index 1a94c318..431d1774 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-native-impl/SharedLibSpanner.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-native-impl/SharedLibSpanner.cs @@ -13,6 +13,7 @@ // limitations under the License. using System; +using System.Threading; using System.Threading.Tasks; using Google.Cloud.Spanner.V1; using Google.Protobuf; @@ -115,9 +116,9 @@ public Rows Execute(Connection connection, ExecuteSqlRequest statement) return new Rows(connection, handler.ObjectId()); } - public Task ExecuteAsync(Connection connection, ExecuteSqlRequest statement) + public Task ExecuteAsync(Connection connection, ExecuteSqlRequest statement, CancellationToken cancellationToken) { - return Task.Run(() => Execute(connection, statement)); + return Task.Run(() => Execute(connection, statement), cancellationToken); } public long[] ExecuteBatch(Connection connection, ExecuteBatchDmlRequest statements) @@ -154,9 +155,9 @@ public long[] ExecuteBatch(Connection connection, ExecuteBatchDmlRequest stateme return result; } - public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequest statements) + public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequest statements, CancellationToken cancellationToken = default) { - return Task.Run(() => ExecuteBatch(connection, statements)); + return Task.Run(() => ExecuteBatch(connection, statements), cancellationToken); } public ResultSetMetadata? Metadata(Rows rows) @@ -165,9 +166,9 @@ public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequ return handler.Length == 0 ? null : ResultSetMetadata.Parser.ParseFrom(handler.Value()); } - public async Task MetadataAsync(Rows rows) + public async Task MetadataAsync(Rows rows, CancellationToken cancellationToken = default) { - return await Task.Run(() => Metadata(rows)); + return await Task.Run(() => Metadata(rows), cancellationToken); } public ResultSetStats? Stats(Rows rows) @@ -182,9 +183,9 @@ public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequ return handler.Length == 0 ? null : ListValue.Parser.ParseFrom(handler.Value()); } - public async Task NextAsync(Rows rows, int numRows, ISpannerLib.RowEncoding encoding) + public async Task NextAsync(Rows rows, int numRows, ISpannerLib.RowEncoding encoding, CancellationToken cancellationToken = default) { - return await Task.Run(() => Next(rows, numRows, encoding)); + return await Task.Run(() => Next(rows, numRows, encoding), cancellationToken); } public void CloseRows(Rows rows) @@ -192,6 +193,11 @@ public void CloseRows(Rows rows) ExecuteAndReleaseLibraryFunction(() => SpannerLib.CloseRows(rows.SpannerConnection.Pool.Id, rows.SpannerConnection.Id, rows.Id)); } + public Task CloseRowsAsync(Rows rows, CancellationToken cancellationToken = default) + { + return Task.Run(() => CloseRows(rows), cancellationToken); + } + public void BeginTransaction(Connection connection, TransactionOptions transactionOptions) { using var handler = ExecuteLibraryFunction(() => @@ -208,8 +214,18 @@ public void BeginTransaction(Connection connection, TransactionOptions transacti return handler.Length == 0 ? null : CommitResponse.Parser.ParseFrom(handler.Value()); } + public Task CommitAsync(Connection connection, CancellationToken cancellationToken = default) + { + return Task.Run(() => Commit(connection), cancellationToken); + } + public void Rollback(Connection connection) { ExecuteAndReleaseLibraryFunction(() => SpannerLib.Rollback(connection.Pool.Id, connection.Id)); } + + public Task RollbackAsync(Connection connection, CancellationToken cancellationToken = default) + { + return Task.Run(() => Rollback(connection), cancellationToken); + } } diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/AbstractMockServerTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/AbstractMockServerTests.cs new file mode 100644 index 00000000..a98b679b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/AbstractMockServerTests.cs @@ -0,0 +1,66 @@ +// Copyright 2025 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 +// +// https://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. + +using Google.Cloud.SpannerLib.Grpc; +using Google.Cloud.SpannerLib.MockServer; +using Google.Cloud.SpannerLib.Native.Impl; +using NUnit.Framework.Internal; + +namespace Google.Cloud.SpannerLib.Tests; + +public abstract class AbstractMockServerTests +{ + public enum LibType + { + Shared, + Grpc, + GrpcTcp, + } + + protected readonly Dictionary SpannerLibDictionary = new([ + new KeyValuePair(LibType.Shared, new SharedLibSpanner()), + new KeyValuePair(LibType.Grpc, new GrpcLibSpanner()), + new KeyValuePair(LibType.GrpcTcp, new GrpcLibSpanner(addressType: Server.AddressType.Tcp)), + ]); + + protected SpannerMockServerFixture Fixture; + + protected string ConnectionString => $"{Fixture.Host}:{Fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; + + [OneTimeSetUp] + public void Setup() + { + Fixture = new SpannerMockServerFixture(); + Fixture.SpannerMock.AddOrUpdateStatementResult("SELECT 1", StatementResult.CreateSelect1ResultSet()); + } + + [OneTimeTearDown] + public void Teardown() + { + foreach (var spannerLib in SpannerLibDictionary.Values) + { + spannerLib.Dispose(); + } + Fixture.Dispose(); + } + + [TearDown] + public void Reset() + { + Fixture.SpannerMock.Reset(); + Fixture.DatabaseAdminMock.Reset(); + Fixture.SpannerMock.AddOrUpdateStatementResult("SELECT 1", StatementResult.CreateSelect1ResultSet()); + } + +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BasicTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BasicTests.cs index 687746f2..81358026 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BasicTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BasicTests.cs @@ -24,46 +24,28 @@ namespace Google.Cloud.SpannerLib.Tests; -public class BasicTests +public class BasicTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - _fixture.SpannerMock.AddOrUpdateStatementResult("SELECT 1", StatementResult.CreateSelect1ResultSet()); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } [Test] - public void TestCreatePool() + public void TestCreatePool([Values] LibType libType) { - var pool = Pool.Create(_spannerLib, ConnectionString); + var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); pool.Close(); } [Test] - public void TestCreateConnection() + public void TestCreateConnection([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); var connection = pool.CreateConnection(); connection.Close(); } [Test] - public void TestExecuteQuery() + public void TestExecuteQuery([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "SELECT 1" }); for (var row = rows.Next(); row != null; row = rows.Next()) @@ -75,12 +57,12 @@ public void TestExecuteQuery() } [Test] - public void TestExecuteQueryError() + public void TestExecuteQueryError([Values] LibType libType) { var sql = "select * from non_existing_table"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateException(new RpcException(new Status(StatusCode.NotFound, "Table not found")))); + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateException(new RpcException(new Status(StatusCode.NotFound, "Table not found")))); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); SpannerException exception = Assert.Throws(() => connection.Execute(new ExecuteSqlRequest { Sql = sql })); Assert.That(exception.Code, Is.EqualTo(Code.NotFound)); @@ -88,15 +70,15 @@ public void TestExecuteQueryError() } [Test] - public void TestExecuteParameterizedQuery() + public void TestExecuteParameterizedQuery([Values] LibType libType) { var sql = "select col_varchar from all_types where col_bigint=$1::bigint"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateSingleColumnResultSet( new Spanner.V1.Type { Code = TypeCode.String }, "col_varchar", "some-value")); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); var parameters = new Struct { @@ -119,15 +101,15 @@ public void TestExecuteParameterizedQuery() } [Test] - public void TestQueryParameterStartingWithUnderscore() + public void TestQueryParameterStartingWithUnderscore([Values] LibType libType) { var sql = "select col_string from all_types where col_int64=@__id"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateSingleColumnResultSet( new Spanner.V1.Type { Code = TypeCode.String }, "col_string", "some-value")); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); var parameters = new Struct { @@ -151,9 +133,9 @@ public void TestQueryParameterStartingWithUnderscore() [Test] [Ignore("execute async disabled for now")] - public async Task TestExecuteQueryAsync() + public async Task TestExecuteQueryAsync([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = await connection.ExecuteAsync(new ExecuteSqlRequest { Sql = "SELECT 1" }); var metadata = rows.Metadata; @@ -167,9 +149,9 @@ public async Task TestExecuteQueryAsync() } [Test] - public void TestReadOnlyTransaction() + public void TestReadOnlyTransaction([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions { ReadOnly = new TransactionOptions.Types.ReadOnly() }); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "SELECT 1" }); @@ -184,11 +166,11 @@ public void TestReadOnlyTransaction() } [Test] - public void TestReadWriteTransaction() + public void TestReadWriteTransaction([Values] LibType libType) { var sql = "update table1 set value='one' where id=1"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateUpdateCount(1)); - using var pool = Pool.Create(_spannerLib, ConnectionString); + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateUpdateCount(1)); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions { ReadWrite = new TransactionOptions.Types.ReadWrite() }); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = sql }); @@ -202,7 +184,7 @@ public void TestReadWriteTransaction() public void TestBenchmarkNativeSpannerLib() { var totalRowCount = 1000000; - _fixture.SpannerMock.AddOrUpdateStatementResult( + Fixture.SpannerMock.AddOrUpdateStatementResult( "select * from all_types", StatementResult.CreateResultSet( new List> @@ -236,7 +218,7 @@ public void TestBenchmarkNativeSpannerLib() public void TestBenchmarkDotnetGrpcClient() { var totalRowCount = 1000000; - _fixture.SpannerMock.AddOrUpdateStatementResult( + Fixture.SpannerMock.AddOrUpdateStatementResult( "select * from all_types", StatementResult.CreateResultSet( new List> @@ -251,7 +233,7 @@ public void TestBenchmarkDotnetGrpcClient() var totalValueCount = totalRowCount * 5; var builder = new SpannerClientBuilder { - Endpoint = $"http://{_fixture.Endpoint}", + Endpoint = $"http://{Fixture.Endpoint}", ChannelCredentials = ChannelCredentials.Insecure }; SpannerClient client = builder.Build(); diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BatchTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BatchTests.cs index e2c95b01..8428e941 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BatchTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BatchTests.cs @@ -15,38 +15,19 @@ using Google.Cloud.Spanner.Admin.Database.V1; using Google.Cloud.Spanner.V1; using Google.Cloud.SpannerLib.MockServer; -using Google.Cloud.SpannerLib.Native.Impl; using Google.Protobuf.WellKnownTypes; namespace Google.Cloud.SpannerLib.Tests; -public class BatchTests +public class BatchTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } - [Test] - public void TestBatchDml() + public void TestBatchDml([Values] LibType libType) { var insert = "insert into test (id, value) values (@id, @value)"; - _fixture.SpannerMock.AddOrUpdateStatementResult(insert, StatementResult.CreateUpdateCount(1)); + Fixture.SpannerMock.AddOrUpdateStatementResult(insert, StatementResult.CreateUpdateCount(1)); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); var updateCounts = connection.ExecuteBatch([ new ExecuteBatchDmlRequest.Types.Statement {Sql = insert, Params = new Struct @@ -67,15 +48,15 @@ public void TestBatchDml() }}, ]); Assert.That(updateCounts, Is.EqualTo(new long[]{1,1})); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestBatchDdl() + public void TestBatchDdl([Values] LibType libType) { // We don't need to set up any results for DDL statements on the mock server. // It automatically responds with an long-running operation that has finished when it receives a DDL request. - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); // The input argument for ExecuteBatch is always a ExecuteBatchDmlRequest, even for DDL statements. var updateCounts = connection.ExecuteBatch([ @@ -83,7 +64,7 @@ public void TestBatchDdl() new ExecuteBatchDmlRequest.Types.Statement {Sql = "create index my_index on my_table (value)"}, ]); Assert.That(updateCounts, Is.EqualTo(new long[]{-1,-1})); - Assert.That(_fixture.DatabaseAdminMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.DatabaseAdminMock.Requests.OfType().Count(), Is.EqualTo(1)); } } \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BenchmarkTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BenchmarkTests.cs new file mode 100644 index 00000000..74504411 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/BenchmarkTests.cs @@ -0,0 +1,197 @@ +// Copyright 2025 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 +// +// https://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. + +using System.Diagnostics; +using Google.Cloud.Spanner.Data; +using Google.Cloud.Spanner.V1; +using Google.Protobuf.WellKnownTypes; + +namespace Google.Cloud.SpannerLib.Tests; + +public class BenchmarkTests : AbstractMockServerTests +{ + readonly struct Stats + { + public TimeSpan Min { get; init; } + public TimeSpan P50 { get; init; } + public TimeSpan P90 { get; init; } + public TimeSpan P95 { get; init; } + public TimeSpan P99 { get; init; } + public TimeSpan Max { get; init; } + public TimeSpan Avg { get; init; } + + public override string ToString() + { + return $"Min: {Min}{Environment.NewLine}" + + $"P50: {P50}{Environment.NewLine}" + + $"P90: {P90}{Environment.NewLine}" + + $"P95: {P95}{Environment.NewLine}" + + $"P99: {P99}{Environment.NewLine}" + + $"Max: {Max}{Environment.NewLine}" + + $"Avg: {Avg}{Environment.NewLine}"; + } + } + + [Test, Sequential] + [Ignore("for local testing")] + public async Task TestBenchmarkRealSpanner([Values] LibType? libType, [Values(false, false, false, true)] bool clientLib) + { + const string connectionString = "projects/appdev-soda-spanner-staging/instances/knut-test-ycsb/databases/knut-test-db"; + const int numTasks = 2000; + object connector; + + if (clientLib) + { + connector = $"Data Source={connectionString}"; + } + else + { + var pool = Pool.Create(SpannerLibDictionary[libType!.Value], connectionString); + connector = pool; + } + + // Warmup + var warmupDuration = await ReadRandomRows(connector, 10); + Console.WriteLine($"Warmup Duration: {warmupDuration}"); + + for (var i = 0; i < 10; i++) + { + var numRows = (i + 1) * 10; + var duration = await ReadRandomRows(connector, numRows); + Console.WriteLine($"Duration ({numRows}): {duration}"); + } + + var stopwatch = Stopwatch.StartNew(); + var tasks = new Task[numTasks]; + for (var i = 0; i < numTasks; i++) + { + tasks[i] = ReadRandomRows(connector, 10); + } + + await Task.WhenAll(tasks); + var durations = new TimeSpan[numTasks]; + for (var i = 0; i < numTasks; i++) + { + durations[i] = tasks[i].Result; + } + var totalDuration = stopwatch.Elapsed; + + var stats = CalculateStats(durations); + Console.WriteLine(); + Console.WriteLine($"Num tasks: {numTasks}"); + Console.WriteLine($"{stats}"); + ThreadPool.GetMaxThreads(out var workerThreads, out _); + Console.WriteLine($"Max threads: {workerThreads}"); + Console.WriteLine($"Total time: {totalDuration}"); + + if (connector is IDisposable disposable) + { + disposable.Dispose(); + } + } + + static Stats CalculateStats(TimeSpan[] durations) + { + var ordered = durations.Order().ToArray(); + var stats = new Stats + { + Min = ordered[0], + P50 = ordered[ordered.Length * 50 / 100], + P90 = ordered[ordered.Length * 90 / 100], + P95 = ordered[ordered.Length * 95 / 100], + P99 = ordered[ordered.Length * 99 / 100], + Max = ordered[^1], + Avg = TimeSpan.FromTicks((long) ordered.Average(duration => duration.Ticks)) + }; + return stats; + } + + static Task ReadRandomRows(object connector, int maxRows) + { + if (connector is Pool pool) + { + return ReadRandomRows(pool, maxRows); + } + if (connector is string connString) + { + return ReadRandomRows(connString, maxRows); + } + throw new NotSupportedException(); + } + + static async Task ReadRandomRows(Pool pool, int maxRows) + { + // Add the randomly selected identifiers to a set to ensure that we know exactly how many rows will be returned, + // as the random selection of identifiers could contain duplicates. + var set = new HashSet(); + var list = Value.ForList(); + list.ListValue.Values.Capacity = maxRows; + for (var c = 0; c < maxRows; c++) + { + var id = Random.Shared.Next(1, 1_000_001); + set.Add(id); + list.ListValue.Values.Add(Value.ForString($"{id}")); + } + await using var connection = pool.CreateConnection(); + + var stopwatch = Stopwatch.StartNew(); + var request = new ExecuteSqlRequest + { + Sql = "select * from all_types where col_bigint = any($1)", + Params = new Struct { Fields = { ["p1"] = list } }, + }; + var count = 0; + await using var rows = await connection.ExecuteAsync(request); + while (await rows.NextAsync() is { } row) + { + Assert.That(row.Values.Count, Is.EqualTo(10)); + count++; + } + Assert.That(count, Is.EqualTo(set.Count)); + + return stopwatch.Elapsed; + } + + static async Task ReadRandomRows(string connectionString, int maxRows) + { + var set = new HashSet(); + var list = new List + { + Capacity = maxRows + }; + for (var c = 0; c < maxRows; c++) + { + var id = Random.Shared.Next(1, 1_000_001); + set.Add(id); + list.Add(id); + } + await using var connection = new SpannerConnection(connectionString); + + var stopwatch = Stopwatch.StartNew(); + await using var cmd = connection.CreateSelectCommand( + "select * from all_types where col_bigint = any($1)", + new SpannerParameterCollection {{"p1", SpannerDbType.ArrayOf(SpannerDbType.Int64), list}} + ); + var count = 0; + await using var rows = await cmd.ExecuteReaderAsync(); + while (await rows.ReadAsync()) + { + Assert.That(rows.FieldCount, Is.EqualTo(10)); + count++; + } + Assert.That(count, Is.EqualTo(set.Count)); + + return stopwatch.Elapsed; + } +} \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/ConnectionTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/ConnectionTests.cs index 1f4e88ea..b6bc88ad 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/ConnectionTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/ConnectionTests.cs @@ -13,47 +13,27 @@ // limitations under the License. using Google.Cloud.Spanner.V1; -using Google.Cloud.SpannerLib.MockServer; -using Google.Cloud.SpannerLib.Native.Impl; using Google.Protobuf.WellKnownTypes; using Google.Rpc; namespace Google.Cloud.SpannerLib.Tests; -public class ConnectionTests +public class ConnectionTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } - [Test] - public void TestCreateConnection() + public void TestCreateConnection([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); Assert.That(connection, Is.Not.Null); Assert.That(connection.Id, Is.GreaterThan(0)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestCreateTwoConnections() + public void TestCreateTwoConnections([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection1 = pool.CreateConnection(); using var connection2 = pool.CreateConnection(); Assert.That(connection1, Is.Not.Null); @@ -61,13 +41,13 @@ public void TestCreateTwoConnections() Assert.That(connection1.Id, Is.GreaterThan(0)); Assert.That(connection2.Id, Is.GreaterThan(0)); Assert.That(connection1.Id, Is.Not.EqualTo(connection2.Id)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestWriteMutations() + public void TestWriteMutations([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); var insertMutation = new Mutation { @@ -99,9 +79,9 @@ public void TestWriteMutations() }); Assert.That(response, Is.Not.Null); Assert.That(response.CommitTimestamp, Is.Not.Null); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - var commit = _fixture.SpannerMock.Requests.OfType().Single(); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + var commit = Fixture.SpannerMock.Requests.OfType().Single(); Assert.That(commit, Is.Not.Null); Assert.That(commit.Mutations.Count, Is.EqualTo(2)); Assert.That(commit.Mutations[0].Insert.Values.Count, Is.EqualTo(2)); @@ -109,9 +89,9 @@ public void TestWriteMutations() } [Test] - public void TestWriteMutationsInTransaction() + public void TestWriteMutationsInTransaction([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions()); @@ -136,18 +116,18 @@ public void TestWriteMutationsInTransaction() response = connection.Commit(); Assert.That(response, Is.Not.Null); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - var commit = _fixture.SpannerMock.Requests.OfType().Single(); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + var commit = Fixture.SpannerMock.Requests.OfType().Single(); Assert.That(commit, Is.Not.Null); Assert.That(commit.Mutations.Count, Is.EqualTo(1)); Assert.That(commit.Mutations[0].Insert.Values.Count, Is.EqualTo(1)); } [Test] - public void TestWriteMutationsInReadOnlyTransaction() + public void TestWriteMutationsInReadOnlyTransaction([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions{ReadOnly = new TransactionOptions.Types.ReadOnly()}); diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/PoolTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/PoolTests.cs index 314770c2..c33ffdbb 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/PoolTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/PoolTests.cs @@ -14,48 +14,29 @@ using Google.Cloud.Spanner.V1; using Google.Cloud.SpannerLib.MockServer; -using Google.Cloud.SpannerLib.Native.Impl; using Google.Rpc; using Grpc.Core; namespace Google.Cloud.SpannerLib.Tests; -public class PoolTests +public class PoolTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } - [Test] - public void TestCreatePool() + public void TestCreatePool([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); Assert.That(pool, Is.Not.Null); Assert.That(pool.Id, Is.GreaterThan(0)); // Creating a pool should create the underlying client and a multiplexed session. - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestCreatePoolFails() + public void TestCreatePoolFails([Values] LibType libType) { - _fixture.SpannerMock.AddOrUpdateExecutionTime(nameof(_fixture.SpannerMock.CreateSession), ExecutionTime.CreateException(StatusCode.PermissionDenied, "Not allowed")); + Fixture.SpannerMock.AddOrUpdateExecutionTime(nameof(Fixture.SpannerMock.CreateSession), ExecutionTime.CreateException(StatusCode.PermissionDenied, "Not allowed")); - SpannerException exception = Assert.Throws(() => Pool.Create(_spannerLib, ConnectionString)); + SpannerException exception = Assert.Throws(() => Pool.Create(SpannerLibDictionary[libType], ConnectionString)); Assert.That(exception.Code, Is.EqualTo(Code.PermissionDenied)); } diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/RowsTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/RowsTests.cs index e45fb226..a4d0d253 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/RowsTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/RowsTests.cs @@ -15,35 +15,17 @@ using Google.Cloud.Spanner.Admin.Database.V1; using Google.Cloud.Spanner.V1; using Google.Cloud.SpannerLib.MockServer; -using Google.Cloud.SpannerLib.Native.Impl; +using Google.Rpc; +using TypeCode = Google.Cloud.Spanner.V1.TypeCode; namespace Google.Cloud.SpannerLib.Tests; -public class RowsTests +public class RowsTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - _fixture.SpannerMock.AddOrUpdateStatementResult("SELECT 1", StatementResult.CreateSelect1ResultSet()); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } - [Test] - public void TestExecuteSelect1() + public void TestExecuteSelect1([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "SELECT 1" }); var numRows = 0; @@ -58,14 +40,28 @@ public void TestExecuteSelect1() } [Test] - public void TestRandomResults() + public void TestEmptyResults([Values] LibType libType) + { + var sql = "select * from (select 1) where false"; + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateSingleColumnResultSet(new Spanner.V1.Type{Code = TypeCode.Int64}, "c")); + + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); + using var connection = pool.CreateConnection(); + using var rows = connection.Execute(new ExecuteSqlRequest { Sql = sql }); + Assert.That(rows.Metadata, Is.Not.Null); + Assert.That(rows.Metadata.RowType.Fields.Count, Is.EqualTo(1)); + Assert.That(rows.Next(), Is.Null); + } + + [Test] + public void TestRandomResults([Values] LibType libType) { var numRows = 10; var rowType = RandomResultSetGenerator.GenerateAllTypesRowType(); var results = RandomResultSetGenerator.Generate(rowType, numRows); - _fixture.SpannerMock.AddOrUpdateStatementResult("select * from random", StatementResult.CreateQuery(results)); + Fixture.SpannerMock.AddOrUpdateStatementResult("select * from random", StatementResult.CreateQuery(results)); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "select * from random" }); @@ -77,48 +73,118 @@ public void TestRandomResults() } Assert.That(rowCount, Is.EqualTo(numRows)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - var request = _fixture.SpannerMock.Requests.OfType().First(); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + var request = Fixture.SpannerMock.Requests.OfType().First(); + Assert.That(request.Transaction?.SingleUse?.ReadOnly?.HasStrong ?? false); + } + + [Test] + public void TestStopHalfway([Values] LibType libType) + { + var numRows = 10; + var rowType = RandomResultSetGenerator.GenerateAllTypesRowType(); + var results = RandomResultSetGenerator.Generate(rowType, numRows); + Fixture.SpannerMock.AddOrUpdateStatementResult("select * from random", StatementResult.CreateQuery(results)); + var stopAfterRows = Random.Shared.Next(1, numRows - 1); + + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); + using var connection = pool.CreateConnection(); + using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "select * from random" }); + Assert.That(rows.Metadata, Is.Not.Null); + Assert.That(rows.Metadata.RowType.Fields.Count, Is.EqualTo(rowType.Fields.Count)); + + var rowCount = 0; + while (rows.Next() is { } row) + { + rowCount++; + Assert.That(row.Values.Count, Is.EqualTo(rowType.Fields.Count)); + if (rowCount == stopAfterRows) + { + break; + } + } + + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + var request = Fixture.SpannerMock.Requests.OfType().First(); Assert.That(request.Transaction?.SingleUse?.ReadOnly?.HasStrong ?? false); } [Test] - public void TestExecuteDml() + public void TestCloseConnectionWithOpenRows([Values] LibType libType) + { + var numRows = 5000; + var rowType = RandomResultSetGenerator.GenerateAllTypesRowType(); + var results = RandomResultSetGenerator.Generate(rowType, numRows); + Fixture.SpannerMock.AddOrUpdateStatementResult("select * from random", StatementResult.CreateQuery(results)); + + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); + using var connection = pool.CreateConnection(); + using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "select * from random" }); + + // Verify that we can fetch the first row. + Assert.That(rows.Next(), Is.Not.Null); + // Close the connection while the rows object is still open. + connection.Close(); + // Getting all the rows should not be possible. + // If the underlying Rows object uses a stream, then it could be that it still receives some rows, but it will + // eventually fail. + var exception = Assert.Throws(() => + { + while (rows.Next() is not null) + { + } + }); + // The error is 'Connection not found' or an internal exception from the underlying driver, depending on exactly + // when the driver detects that the connection and all related objects have been closed. + Assert.That(exception.Code is Code.NotFound or Code.Unknown, Is.True); + + if (libType == LibType.Shared) + { + // TODO: Remove this once it has been fixed in the shared library. + // Closing a Rows object that has already been closed because the connection has been closed, should + // be a no-op. + var closeException = Assert.Throws(() => rows.Close()); + Assert.That(closeException.Code, Is.EqualTo(Code.NotFound)); + } + } + + [Test] + public void TestExecuteDml([Values] LibType libType) { var sql = "update my_table set value=1 where id=2"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateUpdateCount(1L)); + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateUpdateCount(1L)); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = sql }); Assert.That(rows.Next(), Is.Null); Assert.That(rows.UpdateCount, Is.EqualTo(1L)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - var request = _fixture.SpannerMock.Requests.OfType().First(); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + var request = Fixture.SpannerMock.Requests.OfType().First(); Assert.That(request.Transaction?.Begin?.ReadWrite, Is.Not.Null); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestExecuteDdl() + public void TestExecuteDdl([Values] LibType libType) { // The mock DatabaseAdmin server always responds with a finished operation when // UpdateDatabaseDdl is called, so we don't need to set up any results. - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "create my_table (id int64 primary key)" }); Assert.That(rows.Next(), Is.Null); Assert.That(rows.UpdateCount, Is.EqualTo(-1L)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - Assert.That(_fixture.DatabaseAdminMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.DatabaseAdminMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestExecuteClientSideStatement() + public void TestExecuteClientSideStatement([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); using (var rows = connection.Execute(new ExecuteSqlRequest { Sql = "show variable retry_aborts_internally" })) { diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/TransactionTests.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/TransactionTests.cs index 0c55f56c..010fe5bd 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/TransactionTests.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/TransactionTests.cs @@ -14,66 +14,47 @@ using Google.Cloud.Spanner.V1; using Google.Cloud.SpannerLib.MockServer; -using Google.Cloud.SpannerLib.Native.Impl; using Google.Protobuf.WellKnownTypes; using Google.Rpc; namespace Google.Cloud.SpannerLib.Tests; -public class TransactionTests +public class TransactionTests : AbstractMockServerTests { - private readonly ISpannerLib _spannerLib = new SharedLibSpanner(); - - private SpannerMockServerFixture _fixture; - - private string ConnectionString => $"{_fixture.Host}:{_fixture.Port}/projects/p1/instances/i1/databases/d1;UsePlainText=true"; - - [SetUp] - public void Setup() - { - _fixture = new SpannerMockServerFixture(); - } - - [TearDown] - public void Teardown() - { - _fixture.Dispose(); - } - [Test] - public void TestBeginAndCommit() + public void TestBeginAndCommit([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions()); connection.Commit(); // TODO: The library should take a shortcut and just skip committing empty transactions. - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); } [Test] - public void TestBeginAndRollback() + public void TestBeginAndRollback([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions()); connection.Rollback(); // An empty transaction that is rolled back should be a no-op. - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); } [Test] - public void TestReadWriteTransaction() + public void TestReadWriteTransaction([Values] LibType libType) { var updateSql = "update my_table set value=@value where id=@id"; - _fixture.SpannerMock.AddOrUpdateStatementResult(updateSql, StatementResult.CreateUpdateCount(1)); + Fixture.SpannerMock.AddOrUpdateStatementResult(updateSql, StatementResult.CreateUpdateCount(1)); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions()); @@ -98,22 +79,22 @@ public void TestReadWriteTransaction() // There should be no BeginTransaction requests, as the transaction start is inlined with the // first statement. - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - var request = _fixture.SpannerMock.Requests.OfType().Single(); + var request = Fixture.SpannerMock.Requests.OfType().Single(); Assert.That(request.Transaction?.Begin?.ReadWrite, Is.Not.Null); } [Test] - public void TestReadOnlyTransaction() + public void TestReadOnlyTransaction([Values] LibType libType) { var numRows = 5; var sql = "select * from random"; - _fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateQuery(RandomResultSetGenerator.Generate(numRows))); + Fixture.SpannerMock.AddOrUpdateStatementResult(sql, StatementResult.CreateQuery(RandomResultSetGenerator.Generate(numRows))); - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); connection.BeginTransaction(new TransactionOptions { @@ -135,18 +116,18 @@ public void TestReadOnlyTransaction() // There should be no BeginTransaction requests, as the transaction start is inlined with the // first statement. - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); - Assert.That(_fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(1)); + Assert.That(Fixture.SpannerMock.Requests.OfType().Count(), Is.EqualTo(0)); - var request = _fixture.SpannerMock.Requests.OfType().Single(); + var request = Fixture.SpannerMock.Requests.OfType().Single(); Assert.That(request.Transaction?.Begin?.ReadOnly, Is.Not.Null); } [Test] - public void TestBeginTwice() + public void TestBeginTwice([Values] LibType libType) { - using var pool = Pool.Create(_spannerLib, ConnectionString); + using var pool = Pool.Create(SpannerLibDictionary[libType], ConnectionString); using var connection = pool.CreateConnection(); // Try to start two transactions on a connection. connection.BeginTransaction(new TransactionOptions()); diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/spannerlib-dotnet-tests.csproj b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/spannerlib-dotnet-tests.csproj index 7ff1583e..0fb199a0 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/spannerlib-dotnet-tests.csproj +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet-tests/spannerlib-dotnet-tests.csproj @@ -11,6 +11,7 @@ + @@ -22,6 +23,7 @@ + diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet.sln b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet.sln index 9c030840..c12c60ca 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet.sln +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet.sln @@ -10,6 +10,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-tests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-mockserver", "spannerlib-dotnet-mockserver\spannerlib-dotnet-mockserver.csproj", "{218C7FF7-84C7-4415-ABF8-69C5D7FCB6D9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-grpc-server", "spannerlib-dotnet-grpc-server\spannerlib-dotnet-grpc-server.csproj", "{331CF599-8892-46E5-81A3-25793A6BABA8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-grpc-tests", "spannerlib-dotnet-grpc-tests\spannerlib-dotnet-grpc-tests.csproj", "{4B345CB2-82D5-41BC-80FD-D7EC8E8BF679}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-grpc-impl", "spannerlib-dotnet-grpc-impl\spannerlib-dotnet-grpc-impl.csproj", "{60403079-D584-4CB9-AAB7-7AC7FF39BEBE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spannerlib-dotnet-grpc-v1", "spannerlib-dotnet-grpc-v1\spannerlib-dotnet-grpc-v1.csproj", "{C2538D0C-6544-4B44-88A7-02517B786FFD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,5 +44,21 @@ Global {218C7FF7-84C7-4415-ABF8-69C5D7FCB6D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {218C7FF7-84C7-4415-ABF8-69C5D7FCB6D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {218C7FF7-84C7-4415-ABF8-69C5D7FCB6D9}.Release|Any CPU.Build.0 = Release|Any CPU + {331CF599-8892-46E5-81A3-25793A6BABA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {331CF599-8892-46E5-81A3-25793A6BABA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {331CF599-8892-46E5-81A3-25793A6BABA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {331CF599-8892-46E5-81A3-25793A6BABA8}.Release|Any CPU.Build.0 = Release|Any CPU + {4B345CB2-82D5-41BC-80FD-D7EC8E8BF679}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B345CB2-82D5-41BC-80FD-D7EC8E8BF679}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B345CB2-82D5-41BC-80FD-D7EC8E8BF679}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B345CB2-82D5-41BC-80FD-D7EC8E8BF679}.Release|Any CPU.Build.0 = Release|Any CPU + {60403079-D584-4CB9-AAB7-7AC7FF39BEBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60403079-D584-4CB9-AAB7-7AC7FF39BEBE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60403079-D584-4CB9-AAB7-7AC7FF39BEBE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60403079-D584-4CB9-AAB7-7AC7FF39BEBE}.Release|Any CPU.Build.0 = Release|Any CPU + {C2538D0C-6544-4B44-88A7-02517B786FFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2538D0C-6544-4B44-88A7-02517B786FFD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2538D0C-6544-4B44-88A7-02517B786FFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2538D0C-6544-4B44-88A7-02517B786FFD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/AbstractLibObject.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/AbstractLibObject.cs index a40850ae..7de9a28d 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/AbstractLibObject.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/AbstractLibObject.cs @@ -13,6 +13,7 @@ // limitations under the License. using System; +using System.Threading.Tasks; namespace Google.Cloud.SpannerLib; @@ -20,7 +21,7 @@ namespace Google.Cloud.SpannerLib; /// This is the base class for all objects that are created by SpannerLib. It implements IDisposable and automatically /// closes the object in SpannerLib when the object is either being closed, disposed, or finalized. /// -public abstract class AbstractLibObject : IDisposable +public abstract class AbstractLibObject : IDisposable, IAsyncDisposable { internal ISpannerLib Spanner { get; } public long Id { get; } @@ -56,7 +57,13 @@ public void Dispose() Dispose(true); GC.SuppressFinalize(this); } - + + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore().ConfigureAwait(false); + GC.SuppressFinalize(this); + } + public void Close() { Dispose(true); @@ -81,10 +88,35 @@ protected virtual void Dispose(bool disposing) _disposed = true; } } + + protected virtual async ValueTask DisposeAsyncCore() + { + if (_disposed) + { + return; + } + try + { + if (Id > 0) + { + await CloseLibObjectAsync(); + } + } + finally + { + _disposed = true; + } + } /// /// CloseLibObject should be implemented by concrete subclasses and call the corresponding Close function in /// SpannerLib. /// protected abstract void CloseLibObject(); + + protected virtual ValueTask CloseLibObjectAsync() + { + CloseLibObject(); + return default; + } } \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Connection.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Connection.cs index e3abaad1..1ef9943a 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Connection.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Connection.cs @@ -13,6 +13,7 @@ // limitations under the License. using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Google.Cloud.Spanner.V1; @@ -54,6 +55,11 @@ public void BeginTransaction(TransactionOptions transactionOptions) return Spanner.Commit(this); } + public Task CommitAsync(CancellationToken cancellationToken = default) + { + return Spanner.CommitAsync(this, cancellationToken); + } + /// /// Rollbacks the current transaction. /// @@ -62,6 +68,11 @@ public void Rollback() Spanner.Rollback(this); } + public Task RollbackAsync(CancellationToken cancellationToken = default) + { + return Spanner.RollbackAsync(this, cancellationToken); + } + /// /// Writes the given list of mutations to Spanner. If the connection has an active read/write transaction, then the /// mutations will be buffered in the current transaction and sent to Spanner when the transaction is committed. @@ -139,4 +150,9 @@ protected override void CloseLibObject() { Spanner.CloseConnection(this); } + + protected override async ValueTask CloseLibObjectAsync() + { + await Spanner.CloseConnectionAsync(this); + } } diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/ISpannerLib.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/ISpannerLib.cs index c91086ae..5dfd8e48 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/ISpannerLib.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/ISpannerLib.cs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System; +using System.Threading; using System.Threading.Tasks; using Google.Cloud.Spanner.V1; using Google.Protobuf.WellKnownTypes; @@ -24,7 +26,7 @@ namespace Google.Cloud.SpannerLib; /// it as a child process and communicating with it through a gRPC API. The classes in this assembly use this generic /// interface to abstract away the underlying communication method. /// -public interface ISpannerLib +public interface ISpannerLib : IDisposable { /// /// RowEncoding is used to specify the format that SpannerLib should use to return row data. @@ -66,6 +68,14 @@ public enum RowEncoding /// /// The connection to close public void CloseConnection(Connection connection); + + /// + /// Closes the given connection. This also closes any open Rows objects of this connection. Any active transaction + /// on the connection is rolled back. + /// + /// The connection to close + /// The cancellation token + public Task CloseConnectionAsync(Connection connection, CancellationToken cancellationToken = default) => Task.Run(() => CloseConnection(connection), cancellationToken); /// /// Writes an array of mutations to Spanner. The mutations are buffered in the current transaction of the given @@ -97,11 +107,12 @@ public enum RowEncoding /// /// The connection to use to execute the SQL statement /// The statement to execute + /// The cancellation token /// /// A Rows object with the results of the statement. The contents of the Rows object depends on the type of SQL /// statement. /// - public Task ExecuteAsync(Connection connection, ExecuteSqlRequest statement); + public Task ExecuteAsync(Connection connection, ExecuteSqlRequest statement, CancellationToken cancellationToken = default); /// /// Executes a batch of DML or DDL statements on Spanner. The batch may not contain a mix of DML and DDL statements. @@ -116,8 +127,9 @@ public enum RowEncoding /// /// The connection to use to execute the batch /// The DML or DDL statements to execute + /// The cancellation token /// The update count per statement. The update count for a DDL statement is -1. - public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequest statements); + public Task ExecuteBatchAsync(Connection connection, ExecuteBatchDmlRequest statements, CancellationToken cancellationToken = default); /// /// Returns the ResultSetMetadata of a Rows object. This can be used to inspect the type of data that a Rows object @@ -132,8 +144,9 @@ public enum RowEncoding /// contains. /// /// The Rows object to get the metadata of + /// The cancellation token /// The ResultSetMetadata of the given Rows object - public Task MetadataAsync(Rows rows); + public Task MetadataAsync(Rows rows, CancellationToken cancellationToken = default); /// /// Returns the ResultSetStats of a Rows object. This object contains the update count of a DML statement that was @@ -164,8 +177,9 @@ public enum RowEncoding /// The Rows object to return data rows for /// The maximum number of rows to return /// The encoding that should be used for the data rows + /// The cancellation token /// A ListValue with the actual row data, or null if there are no more rows - public Task NextAsync(Rows rows, int numRows, RowEncoding encoding); + public Task NextAsync(Rows rows, int numRows, RowEncoding encoding, CancellationToken cancellationToken = default); /// /// Closes the given Rows object. This releases all resources associated with this statement result. @@ -173,6 +187,13 @@ public enum RowEncoding /// The Rows object to close public void CloseRows(Rows rows); + /// + /// Closes the given Rows object. This releases all resources associated with this statement result. + /// + /// The Rows object to close + /// The cancellation token + public Task CloseRowsAsync(Rows rows, CancellationToken cancellationToken = default) => Task.Run(() => CloseRows(rows), cancellationToken); + /// /// Starts a new transaction on this connection. A connection can have at most one transaction at any time. All /// transactions, including read-only transactions, must be either committed or rolled back. @@ -190,10 +211,30 @@ public enum RowEncoding /// The connection that has the transaction that should be committed /// The CommitResponse of the transaction, or null if it was a read-only transaction public CommitResponse? Commit(Connection connection); + + /// + /// Commits the current transaction on this connection. + /// + /// The connection that has the transaction that should be committed + /// The CommitResponse of the transaction, or null if it was a read-only transaction + /// The cancellation token + public Task CommitAsync(Connection connection, CancellationToken cancellationToken = default); /// /// Rollbacks the current transaction. /// /// The connection that has the transaction that should be rolled back public void Rollback(Connection connection); + + /// + /// Rollbacks the current transaction. + /// + /// The connection that has the transaction that should be rolled back + /// The cancellation token + public Task RollbackAsync(Connection connection, CancellationToken cancellationToken = default); + + void IDisposable.Dispose() + { + // no-op + } } \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Rows.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Rows.cs index 72178e6d..8e18b2da 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Rows.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/Rows.cs @@ -13,6 +13,7 @@ // limitations under the License. using System; +using System.Threading; using System.Threading.Tasks; using Google.Cloud.Spanner.V1; using Google.Protobuf.WellKnownTypes; @@ -29,14 +30,14 @@ public class Rows : AbstractLibObject private ResultSetMetadata? _metadata; - public ResultSetMetadata? Metadata => _metadata ??= Spanner.Metadata(this); + public virtual ResultSetMetadata? Metadata => _metadata ??= Spanner.Metadata(this); private readonly Lazy _stats; /// /// The ResultSetStats of the SQL statement. This is only available once all data rows have been read. /// - private ResultSetStats? Stats => _stats.Value; + protected virtual ResultSetStats? Stats => _stats.Value; /// /// The update count of the SQL statement. This is only available once all data rows have been read. @@ -76,7 +77,7 @@ public Rows(Connection connection, long id, bool initMetadata = true) : base(con /// Returns the next data row from this Rows object. /// /// The next data row or null if there are no more data - public ListValue? Next() + public virtual ListValue? Next() { var res = Spanner.Next(this, 1, ISpannerLib.RowEncoding.Proto); if (res == null && !_stats.IsValueCreated) @@ -91,9 +92,9 @@ public Rows(Connection connection, long id, bool initMetadata = true) : base(con /// Returns the next data row from this Rows object. /// /// The next data row or null if there are no more data - public async Task NextAsync() + public virtual async Task NextAsync(CancellationToken cancellationToken = default) { - return await Spanner.NextAsync(this, 1, ISpannerLib.RowEncoding.Proto); + return await Spanner.NextAsync(this, 1, ISpannerLib.RowEncoding.Proto, cancellationToken); } /// @@ -103,4 +104,10 @@ protected override void CloseLibObject() { Spanner.CloseRows(this); } + + protected override async ValueTask CloseLibObjectAsync() + { + await Spanner.CloseRowsAsync(this); + } + } diff --git a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/SpannerException.cs b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/SpannerException.cs index 3acc98d5..bb87ddb3 100644 --- a/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/SpannerException.cs +++ b/spannerlib/wrappers/spannerlib-dotnet/spannerlib-dotnet/SpannerException.cs @@ -14,6 +14,8 @@ using System; using Google.Rpc; +using Grpc.Core; +using Status = Google.Rpc.Status; namespace Google.Cloud.SpannerLib; @@ -24,6 +26,11 @@ namespace Google.Cloud.SpannerLib; /// The status that was returned by SpannerLib public class SpannerException(Status status) : Exception(status.Message) { + public static SpannerException ToSpannerException(RpcException exception) + { + return new SpannerException(new Status { Code = (int) exception.Status.StatusCode, Message = exception.Message }); + } + public Status Status { get; } = status; public Code Code => (Code)Status.Code; diff --git a/spannerlib/wrappers/spannerlib-java/pom.xml b/spannerlib/wrappers/spannerlib-java/pom.xml index d8549883..c5f51c7d 100644 --- a/spannerlib/wrappers/spannerlib-java/pom.xml +++ b/spannerlib/wrappers/spannerlib-java/pom.xml @@ -16,14 +16,14 @@ com.google.cloud sdk-platform-java-config - 3.52.1 + 3.52.3 com.google.cloud google-cloud-spanner-bom - 6.100.0 + 6.101.1 pom import @@ -70,7 +70,7 @@ net.java.dev.jna jna - 5.17.0 + 5.18.1 @@ -85,12 +85,25 @@ test-jar test + + + net.bytebuddy + byte-buddy + 1.17.7 + test + + + net.bytebuddy + byte-buddy-agent + 1.17.7 + test + com.google.api gax-grpc testlib test - 2.70.0 + 2.70.3 junit diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/GrpcSpannerLibraryImpl.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/GrpcSpannerLibraryImpl.java index ca546179..705ccffe 100644 --- a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/GrpcSpannerLibraryImpl.java +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/GrpcSpannerLibraryImpl.java @@ -41,6 +41,9 @@ import io.grpc.ManagedChannel; import io.grpc.StatusException; import io.grpc.stub.BlockingClientCall; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; /** This implementation communicates with SpannerLib through a gRPC interface. */ public class GrpcSpannerLibraryImpl implements SpannerLibrary { @@ -48,10 +51,26 @@ public class GrpcSpannerLibraryImpl implements SpannerLibrary { private final SpannerLibBlockingV2Stub stub; private final boolean useStreamingRows; + private final List channels; + private final List stubs; + public GrpcSpannerLibraryImpl(Channel channel, boolean useStreamingRows) { this.channel = channel; this.stub = SpannerLibGrpc.newBlockingV2Stub(channel); this.useStreamingRows = useStreamingRows; + + this.channels = null; + this.stubs = null; + } + + public GrpcSpannerLibraryImpl(List channels) { + this.channel = channels.get(0); + this.stub = SpannerLibGrpc.newBlockingV2Stub(channels.get(0)); + this.useStreamingRows = true; + + this.channels = channels; + this.stubs = + channels.stream().map(SpannerLibGrpc::newBlockingV2Stub).collect(Collectors.toList()); } static SpannerLibException toSpannerLibException(StatusException exception) { @@ -86,6 +105,13 @@ private static com.google.cloud.spannerlib.v1.Rows toProto(Rows rows) { @Override public void close() { + if (this.channels != null) { + for (Channel channel : channels) { + if (channel instanceof ManagedChannel) { + ((ManagedChannel) channel).shutdown(); + } + } + } if (this.channel instanceof ManagedChannel) { ((ManagedChannel) this.channel).shutdown(); } @@ -207,6 +233,10 @@ public Rows execute(Connection connection, ExecuteSqlRequest request) { } private Rows executeStreaming(Connection connection, ExecuteSqlRequest request) { + SpannerLibBlockingV2Stub stub = this.stub; + if (stubs != null) { + stub = stubs.get(ThreadLocalRandom.current().nextInt(stubs.size())); + } BlockingClientCall stream = stub.executeStreaming( ExecuteRequest.newBuilder() diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequest.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequest.java new file mode 100644 index 00000000..787fa695 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequest.java @@ -0,0 +1,364 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: google/spannerlib/v1/spannerlib.proto +// Protobuf Java Version: 4.32.1 + +package com.google.cloud.spannerlib.v1; + +/** Protobuf type {@code google.spannerlib.v1.InfoRequest} */ +@com.google.protobuf.Generated +public final class InfoRequest extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spannerlib.v1.InfoRequest) + InfoRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 32, + /* patch= */ 1, + /* suffix= */ "", + InfoRequest.class.getName()); + } + + // Use InfoRequest.newBuilder() to construct. + private InfoRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private InfoRequest() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spannerlib.v1.InfoRequest.class, + com.google.cloud.spannerlib.v1.InfoRequest.Builder.class); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spannerlib.v1.InfoRequest)) { + return super.equals(obj); + } + com.google.cloud.spannerlib.v1.InfoRequest other = + (com.google.cloud.spannerlib.v1.InfoRequest) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(com.google.cloud.spannerlib.v1.InfoRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** Protobuf type {@code google.spannerlib.v1.InfoRequest} */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spannerlib.v1.InfoRequest) + com.google.cloud.spannerlib.v1.InfoRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spannerlib.v1.InfoRequest.class, + com.google.cloud.spannerlib.v1.InfoRequest.Builder.class); + } + + // Construct using com.google.cloud.spannerlib.v1.InfoRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoRequest getDefaultInstanceForType() { + return com.google.cloud.spannerlib.v1.InfoRequest.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoRequest build() { + com.google.cloud.spannerlib.v1.InfoRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoRequest buildPartial() { + com.google.cloud.spannerlib.v1.InfoRequest result = + new com.google.cloud.spannerlib.v1.InfoRequest(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spannerlib.v1.InfoRequest) { + return mergeFrom((com.google.cloud.spannerlib.v1.InfoRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spannerlib.v1.InfoRequest other) { + if (other == com.google.cloud.spannerlib.v1.InfoRequest.getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spannerlib.v1.InfoRequest) + } + + // @@protoc_insertion_point(class_scope:google.spannerlib.v1.InfoRequest) + private static final com.google.cloud.spannerlib.v1.InfoRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spannerlib.v1.InfoRequest(); + } + + public static com.google.cloud.spannerlib.v1.InfoRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public InfoRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequestOrBuilder.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequestOrBuilder.java new file mode 100644 index 00000000..40f8f103 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoRequestOrBuilder.java @@ -0,0 +1,12 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: google/spannerlib/v1/spannerlib.proto +// Protobuf Java Version: 4.32.1 + +package com.google.cloud.spannerlib.v1; + +@com.google.protobuf.Generated +public interface InfoRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spannerlib.v1.InfoRequest) + com.google.protobuf.MessageOrBuilder {} diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponse.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponse.java new file mode 100644 index 00000000..b7dc7f72 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponse.java @@ -0,0 +1,522 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: google/spannerlib/v1/spannerlib.proto +// Protobuf Java Version: 4.32.1 + +package com.google.cloud.spannerlib.v1; + +/** Protobuf type {@code google.spannerlib.v1.InfoResponse} */ +@com.google.protobuf.Generated +public final class InfoResponse extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spannerlib.v1.InfoResponse) + InfoResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 32, + /* patch= */ 1, + /* suffix= */ "", + InfoResponse.class.getName()); + } + + // Use InfoResponse.newBuilder() to construct. + private InfoResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private InfoResponse() { + version_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spannerlib.v1.InfoResponse.class, + com.google.cloud.spannerlib.v1.InfoResponse.Builder.class); + } + + public static final int VERSION_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile java.lang.Object version_ = ""; + + /** + * string version = 1; + * + * @return The version. + */ + @java.lang.Override + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + + /** + * string version = 1; + * + * @return The bytes for version. + */ + @java.lang.Override + public com.google.protobuf.ByteString getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, version_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, version_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spannerlib.v1.InfoResponse)) { + return super.equals(obj); + } + com.google.cloud.spannerlib.v1.InfoResponse other = + (com.google.cloud.spannerlib.v1.InfoResponse) obj; + + if (!getVersion().equals(other.getVersion())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(com.google.cloud.spannerlib.v1.InfoResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** Protobuf type {@code google.spannerlib.v1.InfoResponse} */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spannerlib.v1.InfoResponse) + com.google.cloud.spannerlib.v1.InfoResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spannerlib.v1.InfoResponse.class, + com.google.cloud.spannerlib.v1.InfoResponse.Builder.class); + } + + // Construct using com.google.cloud.spannerlib.v1.InfoResponse.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + version_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spannerlib.v1.SpannerLibProto + .internal_static_google_spannerlib_v1_InfoResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoResponse getDefaultInstanceForType() { + return com.google.cloud.spannerlib.v1.InfoResponse.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoResponse build() { + com.google.cloud.spannerlib.v1.InfoResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoResponse buildPartial() { + com.google.cloud.spannerlib.v1.InfoResponse result = + new com.google.cloud.spannerlib.v1.InfoResponse(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spannerlib.v1.InfoResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.version_ = version_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spannerlib.v1.InfoResponse) { + return mergeFrom((com.google.cloud.spannerlib.v1.InfoResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spannerlib.v1.InfoResponse other) { + if (other == com.google.cloud.spannerlib.v1.InfoResponse.getDefaultInstance()) return this; + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private java.lang.Object version_ = ""; + + /** + * string version = 1; + * + * @return The version. + */ + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * string version = 1; + * + * @return The bytes for version. + */ + public com.google.protobuf.ByteString getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string version = 1; + * + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + version_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * string version = 1; + * + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + * string version = 1; + * + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spannerlib.v1.InfoResponse) + } + + // @@protoc_insertion_point(class_scope:google.spannerlib.v1.InfoResponse) + private static final com.google.cloud.spannerlib.v1.InfoResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spannerlib.v1.InfoResponse(); + } + + public static com.google.cloud.spannerlib.v1.InfoResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public InfoResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spannerlib.v1.InfoResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponseOrBuilder.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponseOrBuilder.java new file mode 100644 index 00000000..c9698fbd --- /dev/null +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/InfoResponseOrBuilder.java @@ -0,0 +1,27 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: google/spannerlib/v1/spannerlib.proto +// Protobuf Java Version: 4.32.1 + +package com.google.cloud.spannerlib.v1; + +@com.google.protobuf.Generated +public interface InfoResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spannerlib.v1.InfoResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * string version = 1; + * + * @return The version. + */ + java.lang.String getVersion(); + + /** + * string version = 1; + * + * @return The bytes for version. + */ + com.google.protobuf.ByteString getVersionBytes(); +} diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibGrpc.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibGrpc.java index 939d2530..643b7cf2 100644 --- a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibGrpc.java +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibGrpc.java @@ -11,6 +11,47 @@ private SpannerLibGrpc() {} public static final java.lang.String SERVICE_NAME = "google.spannerlib.v1.SpannerLib"; // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor< + com.google.cloud.spannerlib.v1.InfoRequest, com.google.cloud.spannerlib.v1.InfoResponse> + getInfoMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "Info", + requestType = com.google.cloud.spannerlib.v1.InfoRequest.class, + responseType = com.google.cloud.spannerlib.v1.InfoResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor< + com.google.cloud.spannerlib.v1.InfoRequest, com.google.cloud.spannerlib.v1.InfoResponse> + getInfoMethod() { + io.grpc.MethodDescriptor< + com.google.cloud.spannerlib.v1.InfoRequest, com.google.cloud.spannerlib.v1.InfoResponse> + getInfoMethod; + if ((getInfoMethod = SpannerLibGrpc.getInfoMethod) == null) { + synchronized (SpannerLibGrpc.class) { + if ((getInfoMethod = SpannerLibGrpc.getInfoMethod) == null) { + SpannerLibGrpc.getInfoMethod = + getInfoMethod = + io.grpc.MethodDescriptor + . + newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "Info")) + .setSampledToLocalTracing(true) + .setRequestMarshaller( + io.grpc.protobuf.ProtoUtils.marshaller( + com.google.cloud.spannerlib.v1.InfoRequest.getDefaultInstance())) + .setResponseMarshaller( + io.grpc.protobuf.ProtoUtils.marshaller( + com.google.cloud.spannerlib.v1.InfoResponse.getDefaultInstance())) + .setSchemaDescriptor(new SpannerLibMethodDescriptorSupplier("Info")) + .build(); + } + } + } + return getInfoMethod; + } + private static volatile io.grpc.MethodDescriptor< com.google.cloud.spannerlib.v1.CreatePoolRequest, com.google.cloud.spannerlib.v1.Pool> getCreatePoolMethod; @@ -735,6 +776,13 @@ public SpannerLibFutureStub newStub( /** */ public interface AsyncService { + /** */ + default void info( + com.google.cloud.spannerlib.v1.InfoRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getInfoMethod(), responseObserver); + } + /** */ default void createPool( com.google.cloud.spannerlib.v1.CreatePoolRequest request, @@ -878,6 +926,14 @@ protected SpannerLibStub build(io.grpc.Channel channel, io.grpc.CallOptions call return new SpannerLibStub(channel, callOptions); } + /** */ + public void info( + com.google.cloud.spannerlib.v1.InfoRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getInfoMethod(), getCallOptions()), request, responseObserver); + } + /** */ public void createPool( com.google.cloud.spannerlib.v1.CreatePoolRequest request, @@ -1036,6 +1092,13 @@ protected SpannerLibBlockingV2Stub build( return new SpannerLibBlockingV2Stub(channel, callOptions); } + /** */ + public com.google.cloud.spannerlib.v1.InfoResponse info( + com.google.cloud.spannerlib.v1.InfoRequest request) throws io.grpc.StatusException { + return io.grpc.stub.ClientCalls.blockingV2UnaryCall( + getChannel(), getInfoMethod(), getCallOptions(), request); + } + /** */ public com.google.cloud.spannerlib.v1.Pool createPool( com.google.cloud.spannerlib.v1.CreatePoolRequest request) throws io.grpc.StatusException { @@ -1169,6 +1232,13 @@ protected SpannerLibBlockingStub build( return new SpannerLibBlockingStub(channel, callOptions); } + /** */ + public com.google.cloud.spannerlib.v1.InfoResponse info( + com.google.cloud.spannerlib.v1.InfoRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getInfoMethod(), getCallOptions(), request); + } + /** */ public com.google.cloud.spannerlib.v1.Pool createPool( com.google.cloud.spannerlib.v1.CreatePoolRequest request) { @@ -1283,6 +1353,14 @@ protected SpannerLibFutureStub build(io.grpc.Channel channel, io.grpc.CallOption return new SpannerLibFutureStub(channel, callOptions); } + /** */ + public com.google.common.util.concurrent.ListenableFuture< + com.google.cloud.spannerlib.v1.InfoResponse> + info(com.google.cloud.spannerlib.v1.InfoRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getInfoMethod(), getCallOptions()), request); + } + /** */ public com.google.common.util.concurrent.ListenableFuture createPool(com.google.cloud.spannerlib.v1.CreatePoolRequest request) { @@ -1385,22 +1463,23 @@ public com.google.common.util.concurrent.ListenableFuture implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -1419,6 +1498,12 @@ private static final class MethodHandlers @java.lang.SuppressWarnings("unchecked") public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { switch (methodId) { + case METHODID_INFO: + serviceImpl.info( + (com.google.cloud.spannerlib.v1.InfoRequest) request, + (io.grpc.stub.StreamObserver) + responseObserver); + break; case METHODID_CREATE_POOL: serviceImpl.createPool( (com.google.cloud.spannerlib.v1.CreatePoolRequest) request, @@ -1522,6 +1607,12 @@ public io.grpc.stub.StreamObserver invoke( public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getInfoMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + com.google.cloud.spannerlib.v1.InfoRequest, + com.google.cloud.spannerlib.v1.InfoResponse>(service, METHODID_INFO))) .addMethod( getCreatePoolMethod(), io.grpc.stub.ServerCalls.asyncUnaryCall( @@ -1670,6 +1761,7 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() { result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) .setSchemaDescriptor(new SpannerLibFileDescriptorSupplier()) + .addMethod(getInfoMethod()) .addMethod(getCreatePoolMethod()) .addMethod(getClosePoolMethod()) .addMethod(getCreateConnectionMethod()) diff --git a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibProto.java b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibProto.java index a1e78d92..37ae2f12 100644 --- a/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibProto.java +++ b/spannerlib/wrappers/spannerlib-java/src/main/java/com/google/cloud/spannerlib/v1/SpannerLibProto.java @@ -25,6 +25,14 @@ public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry r registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry); } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spannerlib_v1_InfoRequest_descriptor; + static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spannerlib_v1_InfoRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spannerlib_v1_InfoResponse_descriptor; + static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spannerlib_v1_InfoResponse_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor internal_static_google_spannerlib_v1_CreatePoolRequest_descriptor; static final com.google.protobuf.GeneratedMessage.FieldAccessorTable @@ -100,87 +108,91 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "oto\032\034google/protobuf/struct.proto\032\"googl" + "e/spanner/v1/result_set.proto\032\037google/sp" + "anner/v1/spanner.proto\032#google/spanner/v" - + "1/transaction.proto\"3\n\021CreatePoolRequest" - + "\022\036\n\021connection_string\030\001 \001(\tB\003\340A\002\"H\n\027Crea" - + "teConnectionRequest\022-\n\004pool\030\001 \001(\0132\032.goog" - + "le.spannerlib.v1.PoolB\003\340A\002\"\223\001\n\016ExecuteRe" - + "quest\0229\n\nconnection\030\001 \001(\0132 .google.spann" - + "erlib.v1.ConnectionB\003\340A\002\022F\n\023execute_sql_" - + "request\030\002 \001(\0132$.google.spanner.v1.Execut" - + "eSqlRequestB\003\340A\002\"\243\001\n\023ExecuteBatchRequest" - + "\0229\n\nconnection\030\001 \001(\0132 .google.spannerlib" - + ".v1.ConnectionB\003\340A\002\022Q\n\031execute_batch_dml" - + "_request\030\002 \001(\0132).google.spanner.v1.Execu" - + "teBatchDmlRequestB\003\340A\002\"\235\001\n\027BeginTransact" - + "ionRequest\0229\n\nconnection\030\001 \001(\0132 .google." - + "spannerlib.v1.ConnectionB\003\340A\002\022G\n\023transac" - + "tion_options\030\002 \001(\0132%.google.spanner.v1.T" - + "ransactionOptionsB\003\340A\002\"\236\001\n\025WriteMutation" - + "sRequest\0229\n\nconnection\030\001 \001(\0132 .google.sp" - + "annerlib.v1.ConnectionB\003\340A\002\022J\n\tmutations" - + "\030\002 \001(\01322.google.spanner.v1.BatchWriteReq" - + "uest.MutationGroupB\003\340A\002\"\027\n\004Pool\022\017\n\002id\030\001 " - + "\001(\003B\003\340A\002\"L\n\nConnection\022-\n\004pool\030\001 \001(\0132\032.g" - + "oogle.spannerlib.v1.PoolB\003\340A\002\022\017\n\002id\030\002 \001(" - + "\003B\003\340A\002\"R\n\004Rows\0229\n\nconnection\030\001 \001(\0132 .goo" - + "gle.spannerlib.v1.ConnectionB\003\340A\002\022\017\n\002id\030" - + "\002 \001(\003B\003\340A\002\"j\n\013NextRequest\022-\n\004rows\030\001 \001(\0132" - + "\032.google.spannerlib.v1.RowsB\003\340A\002\022\025\n\010num_" - + "rows\030\002 \001(\003B\003\340A\002\022\025\n\010encoding\030\003 \001(\003B\003\340A\002\"\321" - + "\001\n\007RowData\022-\n\004rows\030\001 \001(\0132\032.google.spanne" - + "rlib.v1.RowsB\003\340A\002\0226\n\010metadata\030\002 \001(\0132$.go" - + "ogle.spanner.v1.ResultSetMetadata\022-\n\004dat" - + "a\030\003 \003(\0132\032.google.protobuf.ListValueB\003\340A\002" - + "\0220\n\005stats\030\004 \001(\0132!.google.spanner.v1.Resu" - + "ltSetStats\"@\n\017MetadataRequest\022-\n\004rows\030\001 " - + "\001(\0132\032.google.spannerlib.v1.RowsB\003\340A\002\"F\n\025" - + "ResultSetStatsRequest\022-\n\004rows\030\001 \001(\0132\032.go" - + "ogle.spannerlib.v1.RowsB\003\340A\002\"e\n\027Connecti" - + "onStreamRequest\022?\n\017execute_request\030\001 \001(\013" - + "2$.google.spannerlib.v1.ExecuteRequestH\000" - + "B\t\n\007request\"Z\n\030ConnectionStreamResponse\022" - + "2\n\003row\030\001 \001(\0132#.google.spanner.v1.Partial" - + "ResultSetH\000B\n\n\010response2\361\n\n\nSpannerLib\022S" - + "\n\nCreatePool\022\'.google.spannerlib.v1.Crea" - + "tePoolRequest\032\032.google.spannerlib.v1.Poo" - + "l\"\000\022A\n\tClosePool\022\032.google.spannerlib.v1." - + "Pool\032\026.google.protobuf.Empty\"\000\022e\n\020Create" - + "Connection\022-.google.spannerlib.v1.Create" - + "ConnectionRequest\032 .google.spannerlib.v1" - + ".Connection\"\000\022M\n\017CloseConnection\022 .googl" - + "e.spannerlib.v1.Connection\032\026.google.prot" - + "obuf.Empty\"\000\022M\n\007Execute\022$.google.spanner" - + "lib.v1.ExecuteRequest\032\032.google.spannerli" - + "b.v1.Rows\"\000\022[\n\020ExecuteStreaming\022$.google" - + ".spannerlib.v1.ExecuteRequest\032\035.google.s" - + "pannerlib.v1.RowData\"\0000\001\022g\n\014ExecuteBatch" - + "\022).google.spannerlib.v1.ExecuteBatchRequ" - + "est\032*.google.spanner.v1.ExecuteBatchDmlR" - + "esponse\"\000\022N\n\010Metadata\022\032.google.spannerli" - + "b.v1.Rows\032$.google.spanner.v1.ResultSetM" - + "etadata\"\000\022G\n\004Next\022!.google.spannerlib.v1" - + ".NextRequest\032\032.google.protobuf.ListValue" - + "\"\000\022Q\n\016ResultSetStats\022\032.google.spannerlib" - + ".v1.Rows\032!.google.spanner.v1.ResultSetSt" - + "ats\"\000\022A\n\tCloseRows\022\032.google.spannerlib.v" - + "1.Rows\032\026.google.protobuf.Empty\"\000\022[\n\020Begi" - + "nTransaction\022-.google.spannerlib.v1.Begi" - + "nTransactionRequest\032\026.google.protobuf.Em" - + "pty\"\000\022O\n\006Commit\022 .google.spannerlib.v1.C" - + "onnection\032!.google.spanner.v1.CommitResp" - + "onse\"\000\022F\n\010Rollback\022 .google.spannerlib.v" - + "1.Connection\032\026.google.protobuf.Empty\"\000\022b" - + "\n\016WriteMutations\022+.google.spannerlib.v1." - + "WriteMutationsRequest\032!.google.spanner.v" - + "1.CommitResponse\"\000\022w\n\020ConnectionStream\022-" - + ".google.spannerlib.v1.ConnectionStreamRe" - + "quest\032..google.spannerlib.v1.ConnectionS" - + "treamResponse\"\000(\0010\001B\315\001\n\036com.google.cloud" - + ".spannerlib.v1B\017SpannerLibProtoP\001Z>cloud" - + ".google.com/go/spannerlib/apiv1/spannerl" - + "ibpb;spannerlibpb\252\002\032Google.Cloud.Spanner" - + "Lib.V1\312\002\032Google\\Cloud\\SpannerLib\\V1\352\002\035Go" - + "ogle::Cloud::SpannerLib::V1b\006proto3" + + "1/transaction.proto\"\r\n\013InfoRequest\"\037\n\014In" + + "foResponse\022\017\n\007version\030\001 \001(\t\"3\n\021CreatePoo" + + "lRequest\022\036\n\021connection_string\030\001 \001(\tB\003\340A\002" + + "\"H\n\027CreateConnectionRequest\022-\n\004pool\030\001 \001(" + + "\0132\032.google.spannerlib.v1.PoolB\003\340A\002\"\223\001\n\016E" + + "xecuteRequest\0229\n\nconnection\030\001 \001(\0132 .goog" + + "le.spannerlib.v1.ConnectionB\003\340A\002\022F\n\023exec" + + "ute_sql_request\030\002 \001(\0132$.google.spanner.v" + + "1.ExecuteSqlRequestB\003\340A\002\"\243\001\n\023ExecuteBatc" + + "hRequest\0229\n\nconnection\030\001 \001(\0132 .google.sp" + + "annerlib.v1.ConnectionB\003\340A\002\022Q\n\031execute_b" + + "atch_dml_request\030\002 \001(\0132).google.spanner." + + "v1.ExecuteBatchDmlRequestB\003\340A\002\"\235\001\n\027Begin" + + "TransactionRequest\0229\n\nconnection\030\001 \001(\0132 " + + ".google.spannerlib.v1.ConnectionB\003\340A\002\022G\n" + + "\023transaction_options\030\002 \001(\0132%.google.span" + + "ner.v1.TransactionOptionsB\003\340A\002\"\236\001\n\025Write" + + "MutationsRequest\0229\n\nconnection\030\001 \001(\0132 .g" + + "oogle.spannerlib.v1.ConnectionB\003\340A\002\022J\n\tm" + + "utations\030\002 \001(\01322.google.spanner.v1.Batch" + + "WriteRequest.MutationGroupB\003\340A\002\"\027\n\004Pool\022" + + "\017\n\002id\030\001 \001(\003B\003\340A\002\"L\n\nConnection\022-\n\004pool\030\001" + + " \001(\0132\032.google.spannerlib.v1.PoolB\003\340A\002\022\017\n" + + "\002id\030\002 \001(\003B\003\340A\002\"R\n\004Rows\0229\n\nconnection\030\001 \001" + + "(\0132 .google.spannerlib.v1.ConnectionB\003\340A" + + "\002\022\017\n\002id\030\002 \001(\003B\003\340A\002\"j\n\013NextRequest\022-\n\004row" + + "s\030\001 \001(\0132\032.google.spannerlib.v1.RowsB\003\340A\002" + + "\022\025\n\010num_rows\030\002 \001(\003B\003\340A\002\022\025\n\010encoding\030\003 \001(" + + "\003B\003\340A\002\"\321\001\n\007RowData\022-\n\004rows\030\001 \001(\0132\032.googl" + + "e.spannerlib.v1.RowsB\003\340A\002\0226\n\010metadata\030\002 " + + "\001(\0132$.google.spanner.v1.ResultSetMetadat" + + "a\022-\n\004data\030\003 \003(\0132\032.google.protobuf.ListVa" + + "lueB\003\340A\002\0220\n\005stats\030\004 \001(\0132!.google.spanner" + + ".v1.ResultSetStats\"@\n\017MetadataRequest\022-\n" + + "\004rows\030\001 \001(\0132\032.google.spannerlib.v1.RowsB" + + "\003\340A\002\"F\n\025ResultSetStatsRequest\022-\n\004rows\030\001 " + + "\001(\0132\032.google.spannerlib.v1.RowsB\003\340A\002\"e\n\027" + + "ConnectionStreamRequest\022?\n\017execute_reque" + + "st\030\001 \001(\0132$.google.spannerlib.v1.ExecuteR" + + "equestH\000B\t\n\007request\"Z\n\030ConnectionStreamR" + + "esponse\0222\n\003row\030\001 \001(\0132#.google.spanner.v1" + + ".PartialResultSetH\000B\n\n\010response2\302\013\n\nSpan" + + "nerLib\022O\n\004Info\022!.google.spannerlib.v1.In" + + "foRequest\032\".google.spannerlib.v1.InfoRes" + + "ponse\"\000\022S\n\nCreatePool\022\'.google.spannerli" + + "b.v1.CreatePoolRequest\032\032.google.spannerl" + + "ib.v1.Pool\"\000\022A\n\tClosePool\022\032.google.spann" + + "erlib.v1.Pool\032\026.google.protobuf.Empty\"\000\022" + + "e\n\020CreateConnection\022-.google.spannerlib." + + "v1.CreateConnectionRequest\032 .google.span" + + "nerlib.v1.Connection\"\000\022M\n\017CloseConnectio" + + "n\022 .google.spannerlib.v1.Connection\032\026.go" + + "ogle.protobuf.Empty\"\000\022M\n\007Execute\022$.googl" + + "e.spannerlib.v1.ExecuteRequest\032\032.google." + + "spannerlib.v1.Rows\"\000\022[\n\020ExecuteStreaming" + + "\022$.google.spannerlib.v1.ExecuteRequest\032\035" + + ".google.spannerlib.v1.RowData\"\0000\001\022g\n\014Exe" + + "cuteBatch\022).google.spannerlib.v1.Execute" + + "BatchRequest\032*.google.spanner.v1.Execute" + + "BatchDmlResponse\"\000\022N\n\010Metadata\022\032.google." + + "spannerlib.v1.Rows\032$.google.spanner.v1.R" + + "esultSetMetadata\"\000\022G\n\004Next\022!.google.span" + + "nerlib.v1.NextRequest\032\032.google.protobuf." + + "ListValue\"\000\022Q\n\016ResultSetStats\022\032.google.s" + + "pannerlib.v1.Rows\032!.google.spanner.v1.Re" + + "sultSetStats\"\000\022A\n\tCloseRows\022\032.google.spa" + + "nnerlib.v1.Rows\032\026.google.protobuf.Empty\"" + + "\000\022[\n\020BeginTransaction\022-.google.spannerli" + + "b.v1.BeginTransactionRequest\032\026.google.pr" + + "otobuf.Empty\"\000\022O\n\006Commit\022 .google.spanne" + + "rlib.v1.Connection\032!.google.spanner.v1.C" + + "ommitResponse\"\000\022F\n\010Rollback\022 .google.spa" + + "nnerlib.v1.Connection\032\026.google.protobuf." + + "Empty\"\000\022b\n\016WriteMutations\022+.google.spann" + + "erlib.v1.WriteMutationsRequest\032!.google." + + "spanner.v1.CommitResponse\"\000\022w\n\020Connectio" + + "nStream\022-.google.spannerlib.v1.Connectio" + + "nStreamRequest\032..google.spannerlib.v1.Co" + + "nnectionStreamResponse\"\000(\0010\001B\315\001\n\036com.goo" + + "gle.cloud.spannerlib.v1B\017SpannerLibProto" + + "P\001Z>cloud.google.com/go/spannerlib/apiv1" + + "/spannerlibpb;spannerlibpb\252\002\032Google.Clou" + + "d.SpannerLib.V1\312\002\032Google\\Cloud\\SpannerLi" + + "b\\V1\352\002\035Google::Cloud::SpannerLib::V1b\006pr" + + "oto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( @@ -193,8 +205,21 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { com.google.spanner.v1.SpannerProto.getDescriptor(), com.google.spanner.v1.TransactionProto.getDescriptor(), }); - internal_static_google_spannerlib_v1_CreatePoolRequest_descriptor = + internal_static_google_spannerlib_v1_InfoRequest_descriptor = getDescriptor().getMessageTypes().get(0); + internal_static_google_spannerlib_v1_InfoRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spannerlib_v1_InfoRequest_descriptor, new java.lang.String[] {}); + internal_static_google_spannerlib_v1_InfoResponse_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_google_spannerlib_v1_InfoResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spannerlib_v1_InfoResponse_descriptor, + new java.lang.String[] { + "Version", + }); + internal_static_google_spannerlib_v1_CreatePoolRequest_descriptor = + getDescriptor().getMessageTypes().get(2); internal_static_google_spannerlib_v1_CreatePoolRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_CreatePoolRequest_descriptor, @@ -202,7 +227,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "ConnectionString", }); internal_static_google_spannerlib_v1_CreateConnectionRequest_descriptor = - getDescriptor().getMessageTypes().get(1); + getDescriptor().getMessageTypes().get(3); internal_static_google_spannerlib_v1_CreateConnectionRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_CreateConnectionRequest_descriptor, @@ -210,7 +235,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Pool", }); internal_static_google_spannerlib_v1_ExecuteRequest_descriptor = - getDescriptor().getMessageTypes().get(2); + getDescriptor().getMessageTypes().get(4); internal_static_google_spannerlib_v1_ExecuteRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_ExecuteRequest_descriptor, @@ -218,7 +243,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Connection", "ExecuteSqlRequest", }); internal_static_google_spannerlib_v1_ExecuteBatchRequest_descriptor = - getDescriptor().getMessageTypes().get(3); + getDescriptor().getMessageTypes().get(5); internal_static_google_spannerlib_v1_ExecuteBatchRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_ExecuteBatchRequest_descriptor, @@ -226,7 +251,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Connection", "ExecuteBatchDmlRequest", }); internal_static_google_spannerlib_v1_BeginTransactionRequest_descriptor = - getDescriptor().getMessageTypes().get(4); + getDescriptor().getMessageTypes().get(6); internal_static_google_spannerlib_v1_BeginTransactionRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_BeginTransactionRequest_descriptor, @@ -234,14 +259,14 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Connection", "TransactionOptions", }); internal_static_google_spannerlib_v1_WriteMutationsRequest_descriptor = - getDescriptor().getMessageTypes().get(5); + getDescriptor().getMessageTypes().get(7); internal_static_google_spannerlib_v1_WriteMutationsRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_WriteMutationsRequest_descriptor, new java.lang.String[] { "Connection", "Mutations", }); - internal_static_google_spannerlib_v1_Pool_descriptor = getDescriptor().getMessageTypes().get(6); + internal_static_google_spannerlib_v1_Pool_descriptor = getDescriptor().getMessageTypes().get(8); internal_static_google_spannerlib_v1_Pool_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_Pool_descriptor, @@ -249,14 +274,15 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Id", }); internal_static_google_spannerlib_v1_Connection_descriptor = - getDescriptor().getMessageTypes().get(7); + getDescriptor().getMessageTypes().get(9); internal_static_google_spannerlib_v1_Connection_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_Connection_descriptor, new java.lang.String[] { "Pool", "Id", }); - internal_static_google_spannerlib_v1_Rows_descriptor = getDescriptor().getMessageTypes().get(8); + internal_static_google_spannerlib_v1_Rows_descriptor = + getDescriptor().getMessageTypes().get(10); internal_static_google_spannerlib_v1_Rows_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_Rows_descriptor, @@ -264,7 +290,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Connection", "Id", }); internal_static_google_spannerlib_v1_NextRequest_descriptor = - getDescriptor().getMessageTypes().get(9); + getDescriptor().getMessageTypes().get(11); internal_static_google_spannerlib_v1_NextRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_NextRequest_descriptor, @@ -272,7 +298,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Rows", "NumRows", "Encoding", }); internal_static_google_spannerlib_v1_RowData_descriptor = - getDescriptor().getMessageTypes().get(10); + getDescriptor().getMessageTypes().get(12); internal_static_google_spannerlib_v1_RowData_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_RowData_descriptor, @@ -280,7 +306,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Rows", "Metadata", "Data", "Stats", }); internal_static_google_spannerlib_v1_MetadataRequest_descriptor = - getDescriptor().getMessageTypes().get(11); + getDescriptor().getMessageTypes().get(13); internal_static_google_spannerlib_v1_MetadataRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_MetadataRequest_descriptor, @@ -288,7 +314,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Rows", }); internal_static_google_spannerlib_v1_ResultSetStatsRequest_descriptor = - getDescriptor().getMessageTypes().get(12); + getDescriptor().getMessageTypes().get(14); internal_static_google_spannerlib_v1_ResultSetStatsRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_ResultSetStatsRequest_descriptor, @@ -296,7 +322,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "Rows", }); internal_static_google_spannerlib_v1_ConnectionStreamRequest_descriptor = - getDescriptor().getMessageTypes().get(13); + getDescriptor().getMessageTypes().get(15); internal_static_google_spannerlib_v1_ConnectionStreamRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_ConnectionStreamRequest_descriptor, @@ -304,7 +330,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { "ExecuteRequest", "Request", }); internal_static_google_spannerlib_v1_ConnectionStreamResponse_descriptor = - getDescriptor().getMessageTypes().get(14); + getDescriptor().getMessageTypes().get(16); internal_static_google_spannerlib_v1_ConnectionStreamResponse_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_google_spannerlib_v1_ConnectionStreamResponse_descriptor, diff --git a/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/AbstractSpannerLibTest.java b/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/AbstractSpannerLibTest.java index 712bc36d..4ecea7b3 100644 --- a/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/AbstractSpannerLibTest.java +++ b/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/AbstractSpannerLibTest.java @@ -18,9 +18,11 @@ import com.google.cloud.spanner.connection.AbstractMockServerTest; import com.google.common.collect.ImmutableList; -import io.grpc.ManagedChannel; +import io.grpc.Channel; import io.grpc.ManagedChannelBuilder; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -81,9 +83,16 @@ public void maybeCreateLibrary() throws Exception { private SpannerLibrary createLibrary() { if (libraryType == PoolTest.LibraryType.GRPC) { - ManagedChannel channel = - ManagedChannelBuilder.forTarget(grpcServerAddress).usePlaintext().build(); - return new GrpcSpannerLibraryImpl(channel, true); + int numChannels = 20; + List channels = new ArrayList<>(numChannels); + for (int i = 0; i < numChannels; i++) { + channels.add(ManagedChannelBuilder.forTarget(grpcServerAddress).usePlaintext().build()); + } + return new GrpcSpannerLibraryImpl(channels); + + // ManagedChannel channel = + // ManagedChannelBuilder.forTarget(grpcServerAddress).usePlaintext().build(); + // return new GrpcSpannerLibraryImpl(channel, true); } else if (libraryType == PoolTest.LibraryType.SHARED) { return NativeSpannerLibraryImpl.getInstance(); } else { diff --git a/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/BenchmarkTest.java b/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/BenchmarkTest.java new file mode 100644 index 00000000..60d29aeb --- /dev/null +++ b/spannerlib/wrappers/spannerlib-java/src/test/java/com/google/cloud/spannerlib/BenchmarkTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2025 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.spannerlib; + +import static org.junit.Assert.assertEquals; + +import com.google.common.base.Stopwatch; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.ListValue; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import com.google.spanner.v1.ExecuteSqlRequest; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadLocalRandom; +import org.junit.Ignore; +import org.junit.Test; + +public class BenchmarkTest extends AbstractSpannerLibTest { + static class Stats { + public final Duration min; + public final Duration p50; + public final Duration p90; + public final Duration p95; + public final Duration p99; + public final Duration max; + public final Duration avg; + + public Stats( + Duration min, + Duration p50, + Duration p90, + Duration p95, + Duration p99, + Duration max, + Duration avg) { + this.min = min; + this.p50 = p50; + this.p90 = p90; + this.p95 = p95; + this.p99 = p99; + this.max = max; + this.avg = avg; + } + + @Override + public String toString() { + return String.format( + "Min: %s\n" + + "P50: %s\n" + + "P90: %s\n" + + "P95: %s\n" + + "P99: %s\n" + + "Max: %s\n" + + "Avg: %s\n", + min, p50, p90, p95, p99, max, avg); + } + } + + @Test + @Ignore("For local testing") + public void testBenchmarkRealSpanner() throws Exception { + try (Pool pool = + Pool.createPool( + library, + "projects/appdev-soda-spanner-staging/instances/knut-test-ycsb/databases/knut-test-db")) { + Duration warmupDuration = readRandomRows(pool, 10); + System.out.printf("Warmup duration: %s%n", warmupDuration); + + for (int i = 0; i < 10; i++) { + int numRows = (i + 1) * 10; + Duration duration = readRandomRows(pool, numRows); + System.out.printf("Duration (%d): %s%n", numRows, duration); + } + + int numThreads = 100; + int numTasks = 200; + ListeningExecutorService executor = + MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); + List> futures = new ArrayList<>(numTasks); + for (int i = 0; i < numTasks; i++) { + futures.add(executor.submit(() -> readRandomRows(pool, 10))); + } + Futures.allAsList(futures).get(); + Stats stats = calculateStats(new ArrayList<>(Futures.allAsList(futures).get())); + System.out.println(); + System.out.printf("Num tasks: %d\n", numTasks); + System.out.println(stats); + } + } + + private static Stats calculateStats(List durations) { + durations.sort(Duration::compareTo); + return new Stats( + durations.get(0), + durations.get(durations.size() * 50 / 100), + durations.get(durations.size() * 90 / 100), + durations.get(durations.size() * 95 / 100), + durations.get(durations.size() * 99 / 100), + durations.get(durations.size() - 1), + Duration.ofNanos( + (long) durations.stream().mapToLong(Duration::toNanos).average().orElse(0.0d))); + } + + private static Duration readRandomRows(Pool pool, int maxRows) { + HashSet set = new HashSet(); + ListValue.Builder builder = ListValue.newBuilder(); + for (int c = 0; c < maxRows; c++) { + int id = ThreadLocalRandom.current().nextInt(1, 1_000_001); + set.add(id); + builder.addValues(Value.newBuilder().setStringValue(String.valueOf(id)).build()); + } + try (Connection connection = pool.createConnection()) { + Stopwatch stopwatch = Stopwatch.createStarted(); + ExecuteSqlRequest request = + ExecuteSqlRequest.newBuilder() + .setSql("select * from all_types where col_bigint = any($1)") + .setParams( + Struct.newBuilder() + .putFields("p1", Value.newBuilder().setListValue(builder.build()).build()) + .build()) + .build(); + int count = 0; + try (Rows rows = connection.execute(request)) { + ListValue row; + while ((row = rows.next()) != null) { + assertEquals(10, row.getValuesList().size()); + count++; + } + assertEquals(set.size(), count); + } + return stopwatch.elapsed(); + } + } +} diff --git a/spannerlib/wrappers/spannerlib-ruby/.gitignore b/spannerlib/wrappers/spannerlib-ruby/.gitignore new file mode 100644 index 00000000..c458d7fd --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/.gitignore @@ -0,0 +1,16 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +.rspec_status +/vendor/bundle +/shared/ +*.gem + +.DS_Store +*.swp \ No newline at end of file diff --git a/spannerlib/wrappers/spannerlib-ruby/.rspec b/spannerlib/wrappers/spannerlib-ruby/.rspec new file mode 100644 index 00000000..34c5164d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/.rspec @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/spannerlib/wrappers/spannerlib-ruby/.rubocop.yml b/spannerlib/wrappers/spannerlib-ruby/.rubocop.yml new file mode 100644 index 00000000..40dda27b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/.rubocop.yml @@ -0,0 +1,32 @@ +AllCops: + NewCops: enable + SuggestExtensions: false + Exclude: + - 'lib/spanner_pb.rb' + - 'vendor/**/*' + +plugins: + - rubocop-rspec + +Layout/LineLength: + Max: 150 + +Style/Documentation: + Enabled: false + +RSpec/ExampleLength: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false + +# Add this block to disable the 'let' rule +RSpec/InstanceVariable: + Enabled: false +RSpec/BeforeAfterAll: + Enabled: false +RSpec/DescribeClass: + Exclude: + - 'spec/integration/**/*' + +Style/StringLiterals: + EnforcedStyle: double_quotes diff --git a/spannerlib/wrappers/spannerlib-ruby/Gemfile b/spannerlib/wrappers/spannerlib-ruby/Gemfile new file mode 100644 index 00000000..a40cfd66 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/Gemfile @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +gem "rake", "~> 13.0" + +group :development, :test do + gem "rake-compiler", "~> 1.0" + gem "rspec", "~> 3.0" + gem "rubocop", require: false + gem "rubocop-rspec", require: false +end diff --git a/spannerlib/wrappers/spannerlib-ruby/Rakefile b/spannerlib/wrappers/spannerlib-ruby/Rakefile new file mode 100644 index 00000000..c6babf0a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/Rakefile @@ -0,0 +1,45 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rspec/core/rake_task" +require "rubocop/rake_task" +require "rbconfig" + +RSpec::Core::RakeTask.new(:spec) + +RuboCop::RakeTask.new + +task :compile do + go_source_dir = File.expand_path("../../shared", __dir__) + target_dir = File.expand_path("lib/spannerlib/#{RbConfig::CONFIG['arch']}", __dir__) + output_file = File.join(target_dir, "spannerlib.#{RbConfig::CONFIG['SOEXT']}") + + mkdir_p target_dir + + command = [ + "go", "build", + "-buildmode=c-shared", + "-o", output_file, + go_source_dir + ].join(" ") + + puts command + sh command +end + +task default: %i[compile spec rubocop] + diff --git a/spannerlib/wrappers/spannerlib-ruby/bin/console b/spannerlib/wrappers/spannerlib-ruby/bin/console new file mode 100755 index 00000000..951cbd1b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/bin/console @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "spannerlib/ruby" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +require "irb" +IRB.start(__FILE__) diff --git a/spannerlib/wrappers/spannerlib-ruby/bin/setup b/spannerlib/wrappers/spannerlib-ruby/bin/setup new file mode 100755 index 00000000..dce67d86 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/connection.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/connection.rb new file mode 100644 index 00000000..ea824a7c --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/connection.rb @@ -0,0 +1,106 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require_relative "ffi" + +class Connection + attr_reader :pool_id, :conn_id + + def initialize(pool_id, conn_id) + @pool_id = pool_id + @conn_id = conn_id + end + + # Accepts either an object that responds to `to_proto` or a raw string/bytes + # containing the serialized mutation proto. We avoid requiring the protobuf + # definitions at load time so specs that don't need them can run. + def write_mutations(mutation_group) + req_bytes = if mutation_group.respond_to?(:to_proto) + mutation_group.to_proto + elsif mutation_group.is_a?(String) + mutation_group + else + mutation_group.to_s + end + + SpannerLib.write_mutations(@pool_id, @conn_id, req_bytes) + end + + # Begin a read/write transaction on this connection. Accepts TransactionOptions proto or bytes. + # Returns message bytes (or nil) — higher-level parsing not implemented here. + def begin_transaction(transaction_options = nil) + bytes = if transaction_options.respond_to?(:to_proto) + transaction_options.to_proto + else + transaction_options.is_a?(String) ? transaction_options : transaction_options&.to_s + end + SpannerLib.begin_transaction(@pool_id, @conn_id, bytes) + end + + # Commit the current transaction. Returns CommitResponse bytes or nil. + def commit + SpannerLib.commit(@pool_id, @conn_id) + end + + # Rollback the current transaction. + def rollback + SpannerLib.rollback(@pool_id, @conn_id) + nil + end + + # Execute SQL request (expects a request object with to_proto or raw bytes). Returns message bytes (or nil). + def execute(request) + bytes = if request.respond_to?(:to_proto) + request.to_proto + else + request.is_a?(String) ? request : request.to_s + end + SpannerLib.execute(@pool_id, @conn_id, bytes) + end + + # Execute batch DML/DDL request. Returns ExecuteBatchDmlResponse bytes (or nil). + def execute_batch(request) + bytes = if request.respond_to?(:to_proto) + request.to_proto + else + request.is_a?(String) ? request : request.to_s + end + SpannerLib.execute_batch(@pool_id, @conn_id, bytes) + end + + # Rows helpers — return raw message bytes (caller should parse them). + def metadata(rows_id) + SpannerLib.metadata(@pool_id, @conn_id, rows_id) + end + + def next_rows(rows_id, num_rows, encoding = 0) + SpannerLib.next(@pool_id, @conn_id, rows_id, num_rows, encoding) + end + + def result_set_stats(rows_id) + SpannerLib.result_set_stats(@pool_id, @conn_id, rows_id) + end + + def close_rows(rows_id) + SpannerLib.close_rows(@pool_id, @conn_id, rows_id) + end + + # Closes this connection. Any active transaction on the connection is rolled back. + def close + SpannerLib.close_connection(@pool_id, @conn_id) + nil + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/exceptions.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/exceptions.rb new file mode 100644 index 00000000..6331652d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/exceptions.rb @@ -0,0 +1,24 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +class SpannerLibException < StandardError + attr_reader :status + + def initialize(msg = nil, status = nil) + super(msg) + @status = status + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ffi.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ffi.rb new file mode 100644 index 00000000..f01059c8 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ffi.rb @@ -0,0 +1,249 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +# rubocop:disable Metrics/ModuleLength + +require "rubygems" +require "bundler/setup" + +require "google/protobuf" +require "google/rpc/status_pb" + +require "ffi" + +module SpannerLib + extend FFI::Library + + def self.library_path + lib_dir = File.expand_path(__dir__) + Dir.glob(File.join(lib_dir, "*/spannerlib.#{FFI::Platform::LIBSUFFIX}")).first + end + + ffi_lib library_path + + class GoString < FFI::Struct + layout :p, :pointer, + :len, :long + end + + # GoBytes is the Ruby representation of a Go byte slice + class GoBytes < FFI::Struct + layout :p, :pointer, + :len, :long, + :cap, :long + end + + # Message is the common return type for all native functions. + class Message < FFI::Struct + layout :pinner, :long_long, + :code, :int, + :objectId, :long_long, + :length, :int, + :pointer, :pointer + end + + # --- Native Function Signatures --- + attach_function :CreatePool, [GoString.by_value], Message.by_value + attach_function :ClosePool, [:int64], Message.by_value + attach_function :CreateConnection, [:int64], Message.by_value + attach_function :CloseConnection, %i[int64 int64], Message.by_value + attach_function :WriteMutations, [:int64, :int64, GoBytes.by_value], Message.by_value + attach_function :BeginTransaction, [:int64, :int64, GoBytes.by_value], Message.by_value + attach_function :Commit, %i[int64 int64], Message.by_value + attach_function :Rollback, %i[int64 int64], Message.by_value + attach_function :Execute, [:int64, :int64, GoBytes.by_value], Message.by_value + attach_function :ExecuteBatch, [:int64, :int64, GoBytes.by_value], Message.by_value + attach_function :Metadata, %i[int64 int64 int64], Message.by_value + attach_function :Next, %i[int64 int64 int64 int32 int32], Message.by_value + attach_function :ResultSetStats, %i[int64 int64 int64], Message.by_value + attach_function :CloseRows, %i[int64 int64 int64], Message.by_value + attach_function :Release, [:int64], :void + + # --- Ruby-friendly Wrappers --- + + def self.create_pool(dsn) + dsn_str = dsn.to_s.dup + dsn_ptr = FFI::MemoryPointer.from_string(dsn_str) + + go_dsn = GoString.new + go_dsn[:p] = dsn_ptr + go_dsn[:len] = dsn_str.bytesize + + message = CreatePool(go_dsn) + handle_object_id_response(message, "CreatePool") + end + + def self.close_pool(pool_id) + message = ClosePool(pool_id) + handle_status_response(message, "ClosePool") + end + + def self.create_connection(pool_id) + message = CreateConnection(pool_id) + handle_object_id_response(message, "CreateConnection") + end + + def self.close_connection(pool_id, conn_id) + message = CloseConnection(pool_id, conn_id) + handle_status_response(message, "CloseConnection") + end + + def self.release(pinner) + Release(pinner) + end + + def self.with_gobytes(bytes) + bytes ||= "" + len = bytes.bytesize + ptr = FFI::MemoryPointer.new(len) + ptr.write_bytes(bytes, 0, len) if len.positive? + + go_bytes = GoBytes.new + go_bytes[:p] = ptr + go_bytes[:len] = len + go_bytes[:cap] = len + + yield(go_bytes) + end + + def self.ensure_release(message) + pinner = message[:pinner] + begin + yield + ensure + release(pinner) if pinner != 0 + end + end + + def self.handle_object_id_response(message, func_name) + ensure_release(message) do + if message[:code] != 0 + error_msg = read_error_message(message) + raise "#{func_name} failed with code #{message[:code]}: #{error_msg}" + end + message[:objectId] + end + end + + def self.handle_status_response(message, func_name) + ensure_release(message) do + if message[:code] != 0 + error_msg = read_error_message(message) + raise "#{func_name} failed with code #{message[:code]}: #{error_msg}" + end + end + nil + end + + # rubocop:disable Metrics/MethodLength + def self.handle_data_response(message, func_name) + ensure_release(message) do + if message[:code] != 0 + error_msg = read_error_message(message) + raise "#{func_name} failed with code #{message[:code]}: #{error_msg}" + end + + len = message[:length] + ptr = message[:pointer] + + if len.positive? && !ptr.null? + ptr.read_bytes(len) + else + "" + end + end + end + # rubocop:enable Metrics/MethodLength + + # rubocop:disable Metrics/MethodLength + def self.read_error_message(message) + len = message[:length] + ptr = message[:pointer] + if len.positive? && !ptr.null? + raw_bytes = ptr.read_bytes(len) + begin + status_proto = ::Google::Rpc::Status.decode(raw_bytes) + "Status Proto { code: #{status_proto.code}, message: '#{status_proto.message}' }" + rescue StandardError => e + clean_string = raw_bytes.encode("UTF-8", invalid: :replace, undef: :replace, replace: "?").strip + "Failed to decode Status proto (code #{message[:code]}): #{e.class}: #{e.message} | Raw: #{clean_string}" + end + else + "No error message provided" + end + end + # rubocop:enable Metrics/MethodLength + + def self.write_mutations(pool_id, conn_id, proto_bytes) + with_gobytes(proto_bytes) do |gobytes| + message = WriteMutations(pool_id, conn_id, gobytes) + handle_data_response(message, "WriteMutations") + end + end + + def self.begin_transaction(pool_id, conn_id, proto_bytes) + with_gobytes(proto_bytes) do |gobytes| + message = BeginTransaction(pool_id, conn_id, gobytes) + handle_data_response(message, "BeginTransaction") + end + end + + def self.commit(pool_id, conn_id) + message = Commit(pool_id, conn_id) + handle_data_response(message, "Commit") + end + + def self.rollback(pool_id, conn_id) + message = Rollback(pool_id, conn_id) + handle_status_response(message, "Rollback") + end + + def self.execute(pool_id, conn_id, proto_bytes) + with_gobytes(proto_bytes) do |gobytes| + message = Execute(pool_id, conn_id, gobytes) + handle_object_id_response(message, "Execute") + end + end + + def self.execute_batch(pool_id, conn_id, proto_bytes) + with_gobytes(proto_bytes) do |gobytes| + message = ExecuteBatch(pool_id, conn_id, gobytes) + handle_data_response(message, "ExecuteBatch") + end + end + + def self.metadata(pool_id, conn_id, rows_id) + message = Metadata(pool_id, conn_id, rows_id) + handle_data_response(message, "Metadata") + end + + def self.next(pool_id, conn_id, rows_id, max_rows, fetch_size) + message = Next(pool_id, conn_id, rows_id, max_rows, fetch_size) + handle_data_response(message, "Next") + end + + def self.result_set_stats(pool_id, conn_id, rows_id) + message = ResultSetStats(pool_id, conn_id, rows_id) + handle_data_response(message, "ResultSetStats") + end + + def self.close_rows(pool_id, conn_id, rows_id) + message = CloseRows(pool_id, conn_id, rows_id) + handle_status_response(message, "CloseRows") + end +end + +# rubocop:enable Metrics/ModuleLength diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/pool.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/pool.rb new file mode 100644 index 00000000..33f7065a --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/pool.rb @@ -0,0 +1,63 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require_relative "ffi" +require_relative "connection" + +class Pool + attr_reader :id + + def initialize(id) + @id = id + @closed = false + end + + # Create a new Pool given a DSN string. Raises SpannerLibException on failure. + def self.create_pool(dsn) + begin + pool_id = SpannerLib.create_pool(dsn) + rescue StandardError => e + raise SpannerLibException, e.message + end + + raise SpannerLibException, "failed to create pool" if pool_id.nil? || pool_id <= 0 + + Pool.new(pool_id) + end + + # Close this pool and free native resources. + def close + return if @closed + + SpannerLib.close_pool(@id) + @closed = true + end + + # Create a new Connection associated with this Pool. + def create_connection + raise SpannerLibException, "pool closed" if @closed + + begin + conn_id = SpannerLib.create_connection(@id) + rescue StandardError => e + raise SpannerLibException, e.message + end + + raise SpannerLibException, "failed to create connection" if conn_id.nil? || conn_id <= 0 + + Connection.new(@id, conn_id) + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby.rb new file mode 100644 index 00000000..d206682b --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby.rb @@ -0,0 +1,24 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require_relative "ruby/version" + +module Spannerlib + module Ruby + class Error < StandardError; end + # Your code goes here... + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby/version.rb b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby/version.rb new file mode 100644 index 00000000..100ee429 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/lib/spannerlib/ruby/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Spannerlib + module Ruby + VERSION = "0.1.0" + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/sig/spannerlib/ruby.rbs b/spannerlib/wrappers/spannerlib-ruby/sig/spannerlib/ruby.rbs new file mode 100644 index 00000000..e76e73dd --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/sig/spannerlib/ruby.rbs @@ -0,0 +1,6 @@ +module Spannerlib + module Ruby + VERSION: String + # See the writing guide of rbs: https://github.com/ruby/rbs#guides + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spannerlib-ruby.gemspec b/spannerlib/wrappers/spannerlib-ruby/spannerlib-ruby.gemspec new file mode 100644 index 00000000..4f746b3d --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spannerlib-ruby.gemspec @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require_relative "lib/spannerlib/ruby/version" + +Gem::Specification.new do |spec| + spec.name = "spannerlib-ruby" + spec.version = Spannerlib::Ruby::VERSION + spec.authors = ["Google LLC"] + spec.email = ["cloud-spanner-developers@googlegroups.com"] + + spec.summary = "Ruby wrapper for the Spanner native library" + spec.description = "Lightweight Ruby FFI bindings for the Spanner native library produced from the Go implementation." + spec.homepage = "https://github.com/googleapis/go-sql-spanner/tree/main/spannerlib/wrappers/spannerlib-ruby" + spec.license = "Apache 2.0 License" + spec.required_ruby_version = ">= 3.1.0" + + spec.metadata["rubygems_mfa_required"] = "true" + + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_dependency "ffi" + spec.add_dependency "google-cloud-spanner-v1", "~> 1.7" + spec.add_dependency "google-protobuf", "~> 3.19" + spec.add_dependency "grpc", "~> 1.60" +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spec/integration/connection_emulator_spec.rb b/spannerlib/wrappers/spannerlib-ruby/spec/integration/connection_emulator_spec.rb new file mode 100644 index 00000000..1149b6a3 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spec/integration/connection_emulator_spec.rb @@ -0,0 +1,165 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require "spec_helper" +require "google/cloud/spanner/v1" + +RSpec.describe "Connection APIs against Spanner emulator", :integration do + before(:all) do + @emulator_host = ENV.fetch("SPANNER_EMULATOR_HOST", nil) + skip "SPANNER_EMULATOR_HOST not set" unless @emulator_host && !@emulator_host.empty? + + require "spannerlib/pool" + @dsn = "projects/your-project-id/instances/test-instance/databases/test-database?autoConfigEmulator=true" + + pool = Pool.create_pool(@dsn) + conn = pool.create_connection + ddl_batch_req = Google::Cloud::Spanner::V1::ExecuteBatchDmlRequest.new( + statements: [ + Google::Cloud::Spanner::V1::ExecuteBatchDmlRequest::Statement.new(sql: "DROP TABLE IF EXISTS test_table"), + Google::Cloud::Spanner::V1::ExecuteBatchDmlRequest::Statement.new( + sql: "CREATE TABLE test_table (id INT64 NOT NULL, name STRING(100)) PRIMARY KEY(id)" + ) + ] + ) + conn.execute_batch(ddl_batch_req) + conn.close + pool.close + end + + before do + @pool = Pool.create_pool(@dsn) + @conn = @pool.create_connection + delete_req = Google::Cloud::Spanner::V1::BatchWriteRequest::MutationGroup.new( + mutations: [ + Google::Cloud::Spanner::V1::Mutation.new( + delete: Google::Cloud::Spanner::V1::Mutation::Delete.new( + table: "test_table", + key_set: Google::Cloud::Spanner::V1::KeySet.new(all: true) + ) + ) + ] + ) + @conn.write_mutations(delete_req) + end + + after do + @conn.close + @pool.close + end + + it "creates a connection pool" do + expect(@pool.id).to be > 0 + expect(@conn.conn_id).to be > 0 + end + + it "creates two connections from the same pool" do + conn2 = @pool.create_connection + expect(@conn.conn_id).not_to eq(conn2.conn_id) + expect(conn2.conn_id).to be > 0 + conn2.close + end + + it "writes and reads data in a read-write transaction" do + @conn.begin_transaction + insert_data_req = Google::Cloud::Spanner::V1::BatchWriteRequest::MutationGroup.new( + mutations: [ + Google::Cloud::Spanner::V1::Mutation.new( + insert: Google::Cloud::Spanner::V1::Mutation::Write.new( + table: "test_table", + columns: %w[id name], + values: [ + Google::Protobuf::ListValue.new(values: [Google::Protobuf::Value.new(string_value: "1"), + Google::Protobuf::Value.new(string_value: "Alice")]), + Google::Protobuf::ListValue.new(values: [Google::Protobuf::Value.new(string_value: "2"), + Google::Protobuf::Value.new(string_value: "Bob")]) + ] + ) + ) + ] + ) + @conn.write_mutations(insert_data_req) + @conn.commit + + select_req = Google::Cloud::Spanner::V1::ExecuteSqlRequest.new(sql: "SELECT id, name FROM test_table ORDER BY id") + rows_id = @conn.execute(select_req) + + all_rows = [] + loop do + row_bytes = @conn.next_rows(rows_id, 1) + break if row_bytes.nil? || row_bytes.empty? + + all_rows << Google::Protobuf::ListValue.decode(row_bytes) + end + @conn.close_rows(rows_id) + + expect(all_rows.length).to eq(2) + expect(all_rows[0].values[1].string_value).to eq("Alice") + end + + it "writes and reads data without an explicit transaction (autocommit)" do + insert_data_req = Google::Cloud::Spanner::V1::BatchWriteRequest::MutationGroup.new( + mutations: [ + Google::Cloud::Spanner::V1::Mutation.new( + insert: Google::Cloud::Spanner::V1::Mutation::Write.new( + table: "test_table", + columns: %w[id name], + values: [ + Google::Protobuf::ListValue.new(values: [Google::Protobuf::Value.new(string_value: "3"), + Google::Protobuf::Value.new(string_value: "Charlie")]), + Google::Protobuf::ListValue.new(values: [Google::Protobuf::Value.new(string_value: "4"), + Google::Protobuf::Value.new(string_value: "David")]) + ] + ) + ) + ] + ) + @conn.write_mutations(insert_data_req) + + select_req = Google::Cloud::Spanner::V1::ExecuteSqlRequest.new(sql: "SELECT id, name FROM test_table ORDER BY id") + rows_id = @conn.execute(select_req) + + all_rows = [] + loop do + row_bytes = @conn.next_rows(rows_id, 1) + break if row_bytes.nil? || row_bytes.empty? + + all_rows << Google::Protobuf::ListValue.decode(row_bytes) + end + @conn.close_rows(rows_id) + + expect(all_rows.length).to eq(2) + expect(all_rows[0].values[1].string_value).to eq("Charlie") + end + + it "raises an error when writing in a read-only transaction" do + transaction_options = Google::Cloud::Spanner::V1::TransactionOptions.new( + read_only: Google::Cloud::Spanner::V1::TransactionOptions::ReadOnly.new(strong: true) + ) + @conn.begin_transaction(transaction_options) + + insert_data_req = Google::Cloud::Spanner::V1::BatchWriteRequest::MutationGroup.new( + mutations: [ + Google::Cloud::Spanner::V1::Mutation.new( + insert: Google::Cloud::Spanner::V1::Mutation::Write.new(table: "test_table") + ) + ] + ) + expect { @conn.write_mutations(insert_data_req) }.to raise_error(RuntimeError, /read-only transactions cannot write/) + + @conn.rollback + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spec/integration/pool_emulator_spec.rb b/spannerlib/wrappers/spannerlib-ruby/spec/integration/pool_emulator_spec.rb new file mode 100644 index 00000000..4f7c0911 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spec/integration/pool_emulator_spec.rb @@ -0,0 +1,42 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "Connection APIs against Spanner emulator", :integration do + before(:all) do + @emulator_host = ENV.fetch("SPANNER_EMULATOR_HOST", nil) + skip "SPANNER_EMULATOR_HOST not set; skipping emulator integration tests" unless @emulator_host && !@emulator_host.empty? + + begin + require "spannerlib/pool" + rescue LoadError, StandardError => e + skip "Could not load native spanner library; skipping emulator integration tests: #{e.class}: #{e.message}" + end + @dsn = "projects/your-project-id/instances/test-instance/databases/test-database?autoConfigEmulator=true" + end + + it "creates a pool and a connection against the emulator" do + pool = Pool.create_pool(@dsn) + expect(pool.id).to be > 0 + + conn = pool.create_connection + expect(conn).to respond_to(:pool_id) + expect(conn).to respond_to(:conn_id) + + expect { pool.close }.not_to raise_error + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/connection_spec.rb b/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/connection_spec.rb new file mode 100644 index 00000000..a9d92cbb --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/connection_spec.rb @@ -0,0 +1,53 @@ +# Copyright 2025 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 +# +# https://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 gove + +# frozen_string_literal: true + +require "spec_helper" +require "spannerlib/pool" +require "spannerlib/ffi" +require "spannerlib/exceptions" + +RSpec.describe Connection do + let(:dsn) { "localhost:1234/projects/p/instances/i/databases/d?usePlainText=true" } + let(:pool) { Pool.create_pool(dsn) } + + before do + allow(SpannerLib).to receive(:create_pool).and_return(1) + end + + describe "creation" do + it "is created by a Pool" do + allow(SpannerLib).to receive(:create_connection).with(1).and_return(2) + + # The object under test is the one returned by `pool.create_connection` + conn = pool.create_connection + + expect(conn).to be_a(Connection) + expect(conn.conn_id).to eq(2) + expect(conn.pool_id).to eq(1) + end + + it "raises a SpannerLibException when the FFI call fails" do + allow(SpannerLib).to receive(:create_connection).with(1).and_raise(StandardError.new("boom")) + + expect { pool.create_connection }.to raise_error(SpannerLibException) + end + + it "raises when the FFI call returns a non-positive id" do + allow(SpannerLib).to receive(:create_connection).with(1).and_return(0) + + expect { pool.create_connection }.to raise_error(SpannerLibException) + end + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/pool_spec.rb b/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/pool_spec.rb new file mode 100644 index 00000000..f6d6a373 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spec/spannerlib/pool_spec.rb @@ -0,0 +1,53 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require "spec_helper" +require "spannerlib/pool" +require "spannerlib/ffi" +require "spannerlib/exceptions" + +RSpec.describe Pool do + let(:dsn) { "localhost:1234/projects/p/instances/i/databases/d?usePlainText=true" } + + describe ".create_pool" do + it "creates a pool and returns an object with id > 0" do + allow(SpannerLib).to receive(:create_pool).with(dsn).and_return(42) + + pool = described_class.create_pool(dsn) + + expect(pool).to be_a(described_class) + expect(pool.id).to be > 0 + end + + it "raises a SpannerLibException when create_session/create_pool fails" do + allow(SpannerLib).to receive(:create_pool).with(dsn).and_raise(StandardError.new("Not allowed")) + + expect { described_class.create_pool(dsn) }.to raise_error(SpannerLibException) + end + + it "raises when create_pool returns nil" do + allow(SpannerLib).to receive(:create_pool).with(dsn).and_return(nil) + + expect { described_class.create_pool(dsn) }.to raise_error(SpannerLibException) + end + + it "raises when create_pool returns a non-positive id" do + allow(SpannerLib).to receive(:create_pool).with(dsn).and_return(0) + + expect { described_class.create_pool(dsn) }.to raise_error(SpannerLibException) + end + end +end diff --git a/spannerlib/wrappers/spannerlib-ruby/spec/spec_helper.rb b/spannerlib/wrappers/spannerlib-ruby/spec/spec_helper.rb new file mode 100644 index 00000000..514ba076 --- /dev/null +++ b/spannerlib/wrappers/spannerlib-ruby/spec/spec_helper.rb @@ -0,0 +1,32 @@ +# Copyright 2025 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 +# +# https://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. + +# frozen_string_literal: true + +require "rubygems" +require "bundler/setup" + +require "spannerlib/ruby" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end diff --git a/statements.go b/statements.go index f7232a7b..147146b5 100644 --- a/statements.go +++ b/statements.go @@ -112,33 +112,45 @@ type executableSetStatement struct { } func (s *executableSetStatement) execContext(ctx context.Context, c *conn, opts *ExecOptions) (driver.Result, error) { - if err := c.setConnectionVariable(s.stmt.Identifier, s.stmt.Literal.Value, s.stmt.IsLocal); err != nil { + if err := s.execute(c); err != nil { return nil, err } return driver.ResultNoRows, nil } func (s *executableSetStatement) queryContext(ctx context.Context, c *conn, opts *ExecOptions) (driver.Rows, error) { - if err := c.setConnectionVariable(s.stmt.Identifier, s.stmt.Literal.Value, s.stmt.IsLocal); err != nil { + if err := s.execute(c); err != nil { return nil, err } return createEmptyRows(opts), nil } +func (s *executableSetStatement) execute(c *conn) error { + if len(s.stmt.Identifiers) != len(s.stmt.Literals) { + return status.Errorf(codes.InvalidArgument, "statement contains %d identifiers, but %d values given", len(s.stmt.Identifiers), len(s.stmt.Literals)) + } + for index := range s.stmt.Identifiers { + if err := c.setConnectionVariable(s.stmt.Identifiers[index], s.stmt.Literals[index].Value, s.stmt.IsLocal, s.stmt.IsTransaction); err != nil { + return err + } + } + return nil +} + // RESET [my_extension.]my_property type executableResetStatement struct { stmt *parser.ParsedResetStatement } func (s *executableResetStatement) execContext(ctx context.Context, c *conn, opts *ExecOptions) (driver.Result, error) { - if err := c.setConnectionVariable(s.stmt.Identifier, "default", false); err != nil { + if err := c.setConnectionVariable(s.stmt.Identifier, "default", false, false); err != nil { return nil, err } return driver.ResultNoRows, nil } func (s *executableResetStatement) queryContext(ctx context.Context, c *conn, opts *ExecOptions) (driver.Rows, error) { - if err := c.setConnectionVariable(s.stmt.Identifier, "default", false); err != nil { + if err := c.setConnectionVariable(s.stmt.Identifier, "default", false, false); err != nil { return nil, err } return createEmptyRows(opts), nil @@ -267,10 +279,19 @@ type executableBeginStatement struct { } func (s *executableBeginStatement) execContext(ctx context.Context, c *conn, opts *ExecOptions) (driver.Result, error) { + if len(s.stmt.Identifiers) != len(s.stmt.Literals) { + return nil, status.Errorf(codes.InvalidArgument, "statement contains %d identifiers, but %d values given", len(s.stmt.Identifiers), len(s.stmt.Literals)) + } _, err := c.BeginTx(ctx, driver.TxOptions{}) if err != nil { return nil, err } + for index := range s.stmt.Identifiers { + if err := c.setConnectionVariable(s.stmt.Identifiers[index], s.stmt.Literals[index].Value /*IsLocal=*/, true /*IsTransaction=*/, true); err != nil { + return nil, err + } + } + return driver.ResultNoRows, nil } diff --git a/transaction.go b/transaction.go index a2db9634..297c6b60 100644 --- a/transaction.go +++ b/transaction.go @@ -22,6 +22,7 @@ import ( "fmt" "log/slog" "math/rand" + "sync" "time" "cloud.google.com/go/spanner" @@ -112,6 +113,10 @@ type readOnlyTransaction struct { boTx *spanner.BatchReadOnlyTransaction logger *slog.Logger close func(result txResult) + + timestampBoundMu sync.Mutex + timestampBoundSet bool + timestampBoundCallback func() spanner.TimestampBound } func (tx *readOnlyTransaction) Commit() error { @@ -160,6 +165,14 @@ func (tx *readOnlyTransaction) Query(ctx context.Context, stmt spanner.Statement } return mi, nil } + if tx.timestampBoundCallback != nil { + tx.timestampBoundMu.Lock() + if !tx.timestampBoundSet { + tx.roTx.WithTimestampBound(tx.timestampBoundCallback()) + tx.timestampBoundSet = true + } + tx.timestampBoundMu.Unlock() + } return &readOnlyRowIterator{tx.roTx.QueryWithOptions(ctx, stmt, execOptions.QueryOptions), stmtType}, nil } diff --git a/transaction_test.go b/transaction_test.go new file mode 100644 index 00000000..0842279b --- /dev/null +++ b/transaction_test.go @@ -0,0 +1,226 @@ +package spannerdriver + +import ( + "context" + "database/sql" + "reflect" + "testing" + + "cloud.google.com/go/spanner/admin/database/apiv1/databasepb" + "cloud.google.com/go/spanner/apiv1/spannerpb" + "github.com/googleapis/go-sql-spanner/testutil" +) + +func TestSetTransactionIsolationLevel(t *testing.T) { + t.Parallel() + + db, server, teardown := setupTestDBConnection(t) + defer teardown() + ctx := context.Background() + + tx, _ := db.BeginTx(ctx, &sql.TxOptions{}) + if _, err := tx.ExecContext(ctx, "set transaction isolation level repeatable read"); err != nil { + t.Fatal(err) + } + _, _ = tx.ExecContext(ctx, testutil.UpdateBarSetFoo) + _ = tx.Commit() + + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("execute requests count mismatch\n Got: %v\nWant: %v", g, w) + } + request := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if request.GetTransaction() == nil || request.GetTransaction().GetBegin() == nil { + t.Fatal("missing begin transaction on ExecuteSqlRequest") + } + if g, w := request.GetTransaction().GetBegin().GetIsolationLevel(), spannerpb.TransactionOptions_REPEATABLE_READ; g != w { + t.Fatalf("begin isolation level mismatch\n Got: %v\nWant: %v", g, w) + } +} + +func TestSetTransactionReadOnly(t *testing.T) { + t.Parallel() + + db, server, teardown := setupTestDBConnection(t) + defer teardown() + ctx := context.Background() + + tx, _ := db.BeginTx(ctx, &sql.TxOptions{}) + if _, err := tx.ExecContext(ctx, "set transaction read only"); err != nil { + t.Fatal(err) + } + row := tx.QueryRowContext(ctx, testutil.SelectFooFromBar, ExecOptions{DirectExecuteQuery: true}) + if err := row.Err(); err != nil { + t.Fatal(err) + } + _ = tx.Commit() + + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("execute requests count mismatch\n Got: %v\nWant: %v", g, w) + } + request := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if request.GetTransaction() == nil || request.GetTransaction().GetBegin() == nil { + t.Fatal("missing begin transaction on ExecuteSqlRequest") + } + // TODO: Enable once transaction_read_only is picked up by the driver. + //readOnly := request.GetTransaction().GetBegin().GetReadOnly() + //if readOnly == nil { + // t.Fatal("missing readOnly on ExecuteSqlRequest") + //} +} + +func TestSetTransactionDeferrable(t *testing.T) { + t.Parallel() + + // SET TRANSACTION [NOT] DEFERRABLE is only supported for PostgreSQL-dialect databases. + db, _, teardown := setupTestDBConnectionWithParamsAndDialect(t, "", databasepb.DatabaseDialect_POSTGRESQL) + defer teardown() + ctx := context.Background() + + tx, _ := db.BeginTx(ctx, &sql.TxOptions{}) + if _, err := tx.ExecContext(ctx, "set transaction deferrable"); err != nil { + t.Fatal(err) + } + row := tx.QueryRowContext(ctx, testutil.SelectFooFromBar, ExecOptions{DirectExecuteQuery: true}) + if err := row.Err(); err != nil { + t.Fatal(err) + } + + // transaction_deferrable is a no-op on Spanner, but the SQL statement is supported for + // PostgreSQL-dialect databases for compatibility reasons. + row = tx.QueryRowContext(ctx, "show transaction_deferrable") + if err := row.Err(); err != nil { + t.Fatal(err) + } + var deferrable bool + if err := row.Scan(&deferrable); err != nil { + t.Fatal(err) + } + _ = tx.Commit() + + if g, w := deferrable, true; g != w { + t.Fatalf("deferrable mismatch\n Got: %v\nWant: %v", g, w) + } +} + +func TestBeginTransactionIsolationLevel(t *testing.T) { + t.Parallel() + + db, server, teardown := setupTestDBConnection(t) + defer teardown() + ctx := context.Background() + + conn, err := db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + defer silentClose(conn) + + if _, err := conn.ExecContext(ctx, "begin transaction isolation level repeatable read"); err != nil { + t.Fatal(err) + } + if _, err := conn.ExecContext(ctx, testutil.UpdateBarSetFoo); err != nil { + t.Fatal(err) + } + if _, err := conn.ExecContext(ctx, "commit"); err != nil { + t.Fatal(err) + } + + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("execute requests count mismatch\n Got: %v\nWant: %v", g, w) + } + request := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if request.GetTransaction() == nil || request.GetTransaction().GetBegin() == nil { + t.Fatal("missing begin transaction on ExecuteSqlRequest") + } + if g, w := request.GetTransaction().GetBegin().GetIsolationLevel(), spannerpb.TransactionOptions_REPEATABLE_READ; g != w { + t.Fatalf("begin isolation level mismatch\n Got: %v\nWant: %v", g, w) + } +} + +func TestBeginTransactionReadOnly(t *testing.T) { + t.Parallel() + + db, server, teardown := setupTestDBConnection(t) + defer teardown() + ctx := context.Background() + + conn, err := db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + defer silentClose(conn) + + if _, err := conn.ExecContext(ctx, "begin transaction read write"); err != nil { + t.Fatal(err) + } + row := conn.QueryRowContext(ctx, testutil.SelectFooFromBar, ExecOptions{DirectExecuteQuery: true}) + var c int64 + // If we don't call row.Scan(..), then the underlying Rows object is not closed. That again means that the + // connection cannot be released. + if err := row.Scan(&c); err != nil { + t.Fatal(err) + } + if _, err := conn.ExecContext(ctx, "commit"); err != nil { + t.Fatal(err) + } + + requests := server.TestSpanner.DrainRequestsFromServer() + executeRequests := testutil.RequestsOfType(requests, reflect.TypeOf(&spannerpb.ExecuteSqlRequest{})) + if g, w := len(executeRequests), 1; g != w { + t.Fatalf("execute requests count mismatch\n Got: %v\nWant: %v", g, w) + } + request := executeRequests[0].(*spannerpb.ExecuteSqlRequest) + if request.GetTransaction() == nil || request.GetTransaction().GetBegin() == nil { + t.Fatal("missing begin transaction on ExecuteSqlRequest") + } + // TODO: Enable once transaction_read_only is picked up by the driver. + //readOnly := request.GetTransaction().GetBegin().GetReadOnly() + //if readOnly == nil { + // t.Fatal("missing readOnly on ExecuteSqlRequest") + //} +} + +func TestBeginTransactionDeferrable(t *testing.T) { + t.Parallel() + + // BEGIN TRANSACTION [NOT] DEFERRABLE is only supported for PostgreSQL-dialect databases. + db, _, teardown := setupTestDBConnectionWithParamsAndDialect(t, "", databasepb.DatabaseDialect_POSTGRESQL) + defer teardown() + ctx := context.Background() + + conn, err := db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + defer silentClose(conn) + + if _, err := conn.ExecContext(ctx, "begin transaction deferrable"); err != nil { + t.Fatal(err) + } + row := conn.QueryRowContext(ctx, testutil.SelectFooFromBar, ExecOptions{DirectExecuteQuery: true}) + var c int64 + if err := row.Scan(&c); err != nil { + t.Fatal(err) + } + + // transaction_deferrable is a no-op on Spanner, but the SQL statement is supported for + // PostgreSQL-dialect databases for compatibility reasons. + row = conn.QueryRowContext(ctx, "show transaction_deferrable") + var deferrable bool + if err := row.Scan(&deferrable); err != nil { + t.Fatal(err) + } + if _, err := conn.ExecContext(ctx, "commit"); err != nil { + t.Fatal(err) + } + + if g, w := deferrable, true; g != w { + t.Fatalf("deferrable mismatch\n Got: %v\nWant: %v", g, w) + } +}