Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion spanner/google/cloud/spanner_v1/gapic/spanner_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,9 @@ def delete_session(
metadata=None,
):
"""
Ends a session, releasing server resources associated with it.
Ends a session, releasing server resources associated with it. This will
asynchronously trigger cancellation of any operations that are running with
this session.

Example:
>>> from google.cloud import spanner_v1
Expand Down Expand Up @@ -790,6 +792,111 @@ def execute_streaming_sql(
request, retry=retry, timeout=timeout, metadata=metadata
)

def execute_batch_dml(
self,
session,
transaction,
statements,
seqno,
retry=google.api_core.gapic_v1.method.DEFAULT,
timeout=google.api_core.gapic_v1.method.DEFAULT,
metadata=None,
):
"""
Executes a batch of SQL DML statements. This method allows many
statements to be run with lower latency than submitting them
sequentially with ``ExecuteSql``.

Statements are executed in order, sequentially.
``ExecuteBatchDmlResponse`` will contain a ``ResultSet`` for each DML
statement that has successfully executed. If a statement fails, its
error status will be returned as part of the
``ExecuteBatchDmlResponse``. Execution will stop at the first failed
statement; the remaining statements will not run.

ExecuteBatchDml is expected to return an OK status with a response even
if there was an error while processing one of the DML statements.
Clients must inspect response.status to determine if there were any
errors while processing the request.

See more details in ``ExecuteBatchDmlRequest`` and
``ExecuteBatchDmlResponse``.

Example:
>>> from google.cloud import spanner_v1
>>>
>>> client = spanner_v1.SpannerClient()
>>>
>>> session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]')
>>>
>>> # TODO: Initialize `transaction`:
>>> transaction = {}
>>>
>>> # TODO: Initialize `statements`:
>>> statements = []
>>>
>>> # TODO: Initialize `seqno`:
>>> seqno = 0
>>>
>>> response = client.execute_batch_dml(session, transaction, statements, seqno)

Args:
session (str): Required. The session in which the DML statements should be performed.
transaction (Union[dict, ~google.cloud.spanner_v1.types.TransactionSelector]): The transaction to use. A ReadWrite transaction is required. Single-use
transactions are not supported (to avoid replay). The caller must either
supply an existing transaction ID or begin a new transaction.

If a dict is provided, it must be of the same form as the protobuf
message :class:`~google.cloud.spanner_v1.types.TransactionSelector`
statements (list[Union[dict, ~google.cloud.spanner_v1.types.Statement]]): The list of statements to execute in this batch. Statements are executed
serially, such that the effects of statement i are visible to statement
i+1. Each statement must be a DML statement. Execution will stop at the
first failed statement; the remaining statements will not run.

REQUIRES: statements\_size() > 0.

If a dict is provided, it must be of the same form as the protobuf
message :class:`~google.cloud.spanner_v1.types.Statement`
seqno (long): A per-transaction sequence number used to identify this request. This is
used in the same space as the seqno in ``ExecuteSqlRequest``. See more
details in ``ExecuteSqlRequest``.
retry (Optional[google.api_core.retry.Retry]): A retry object used
to retry requests. If ``None`` is specified, requests will not
be retried.
timeout (Optional[float]): The amount of time, in seconds, to wait
for the request to complete. Note that if ``retry`` is
specified, the timeout applies to each individual attempt.
metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata
that is provided to the method.

Returns:
A :class:`~google.cloud.spanner_v1.types.ExecuteBatchDmlResponse` instance.

Raises:
google.api_core.exceptions.GoogleAPICallError: If the request
failed for any reason.
google.api_core.exceptions.RetryError: If the request failed due
to a retryable error and retry attempts failed.
ValueError: If the parameters are invalid.
"""
# Wrap the transport method to add retry and timeout logic.
if "execute_batch_dml" not in self._inner_api_calls:
self._inner_api_calls[
"execute_batch_dml"
] = google.api_core.gapic_v1.method.wrap_method(
self.transport.execute_batch_dml,
default_retry=self._method_configs["ExecuteBatchDml"].retry,
default_timeout=self._method_configs["ExecuteBatchDml"].timeout,
client_info=self._client_info,
)

request = spanner_pb2.ExecuteBatchDmlRequest(
session=session, transaction=transaction, statements=statements, seqno=seqno
)
return self._inner_api_calls["execute_batch_dml"](
request, retry=retry, timeout=timeout, metadata=metadata
)

def read(
self,
session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
"retry_codes_name": "non_idempotent",
"retry_params_name": "streaming",
},
"ExecuteBatchDml": {
"timeout_millis": 30000,
"retry_codes_name": "idempotent",
"retry_params_name": "default",
},
"Read": {
"timeout_millis": 30000,
"retry_codes_name": "idempotent",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ def list_sessions(self):
def delete_session(self):
"""Return the gRPC stub for :meth:`SpannerClient.delete_session`.

Ends a session, releasing server resources associated with it.
Ends a session, releasing server resources associated with it. This will
asynchronously trigger cancellation of any operations that are running with
this session.

Returns:
Callable: A callable which accepts the appropriate
Expand Down Expand Up @@ -214,6 +216,36 @@ def execute_streaming_sql(self):
"""
return self._stubs["spanner_stub"].ExecuteStreamingSql

@property
def execute_batch_dml(self):
"""Return the gRPC stub for :meth:`SpannerClient.execute_batch_dml`.

Executes a batch of SQL DML statements. This method allows many
statements to be run with lower latency than submitting them
sequentially with ``ExecuteSql``.

Statements are executed in order, sequentially.
``ExecuteBatchDmlResponse`` will contain a ``ResultSet`` for each DML
statement that has successfully executed. If a statement fails, its
error status will be returned as part of the
``ExecuteBatchDmlResponse``. Execution will stop at the first failed
statement; the remaining statements will not run.

ExecuteBatchDml is expected to return an OK status with a response even
if there was an error while processing one of the DML statements.
Clients must inspect response.status to determine if there were any
errors while processing the request.

See more details in ``ExecuteBatchDmlRequest`` and
``ExecuteBatchDmlResponse``.

Returns:
Callable: A callable which accepts the appropriate
deserialized request object and returns a
deserialized response object.
"""
return self._stubs["spanner_stub"].ExecuteBatchDml

@property
def read(self):
"""Return the gRPC stub for :meth:`SpannerClient.read`.
Expand Down
125 changes: 123 additions & 2 deletions spanner/google/cloud/spanner_v1/proto/spanner.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018 Google LLC
// Copyright 2018 Google LLC.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -11,6 +11,7 @@
// 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.
//

syntax = "proto3";

Expand All @@ -20,6 +21,7 @@ import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";
import "google/spanner/v1/keys.proto";
import "google/spanner/v1/mutation.proto";
import "google/spanner/v1/result_set.proto";
Expand Down Expand Up @@ -80,7 +82,9 @@ service Spanner {
};
}

// Ends a session, releasing server resources associated with it.
// Ends a session, releasing server resources associated with it. This will
// asynchronously trigger cancellation of any operations that are running with
// this session.
rpc DeleteSession(DeleteSessionRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{name=projects/*/instances/*/databases/*/sessions/*}"
Expand Down Expand Up @@ -119,6 +123,32 @@ service Spanner {
};
}

// Executes a batch of SQL DML statements. This method allows many statements
// to be run with lower latency than submitting them sequentially with
// [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql].
//
// Statements are executed in order, sequentially.
// [ExecuteBatchDmlResponse][Spanner.ExecuteBatchDmlResponse] will contain a
// [ResultSet][google.spanner.v1.ResultSet] for each DML statement that has successfully executed. If a
// statement fails, its error status will be returned as part of the
// [ExecuteBatchDmlResponse][Spanner.ExecuteBatchDmlResponse]. Execution will
// stop at the first failed statement; the remaining statements will not run.
//
// ExecuteBatchDml is expected to return an OK status with a response even if
// there was an error while processing one of the DML statements. Clients must
// inspect response.status to determine if there were any errors while
// processing the request.
//
// See more details in
// [ExecuteBatchDmlRequest][Spanner.ExecuteBatchDmlRequest] and
// [ExecuteBatchDmlResponse][Spanner.ExecuteBatchDmlResponse].
rpc ExecuteBatchDml(ExecuteBatchDmlRequest) returns (ExecuteBatchDmlResponse) {
option (google.api.http) = {
post: "/v1/{session=projects/*/instances/*/databases/*/sessions/*}:executeBatchDml"
body: "*"
};
}

// Reads rows from the database using key lookups and scans, as a
// simple key/value style alternative to
// [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql]. This method cannot be
Expand Down Expand Up @@ -421,6 +451,97 @@ message ExecuteSqlRequest {
int64 seqno = 9;
}

// The request for [ExecuteBatchDml][google.spanner.v1.Spanner.ExecuteBatchDml]
message ExecuteBatchDmlRequest {
// A single DML statement.
message Statement {
// Required. The DML string.
string sql = 1;

// The DML string can contain parameter placeholders. A parameter
// placeholder consists of `'@'` followed by the parameter
// name. Parameter names consist of any combination of letters,
// numbers, and underscores.
//
// Parameters can appear anywhere that a literal value is expected. The
// same parameter name can be used more than once, for example:
// `"WHERE id > @msg_id AND id < @msg_id + 100"`
//
// It is an error to execute an SQL statement with unbound parameters.
//
// Parameter values are specified using `params`, which is a JSON
// object whose keys are parameter names, and whose values are the
// corresponding parameter values.
google.protobuf.Struct params = 2;

// It is not always possible for Cloud Spanner to infer the right SQL type
// from a JSON value. For example, values of type `BYTES` and values
// of type `STRING` both appear in [params][google.spanner.v1.ExecuteBatchDmlRequest.Statement.params] as JSON strings.
//
// In these cases, `param_types` can be used to specify the exact
// SQL type for some or all of the SQL statement parameters. See the
// definition of [Type][google.spanner.v1.Type] for more information
// about SQL types.
map<string, Type> param_types = 3;
}

// Required. The session in which the DML statements should be performed.
string session = 1;

// The transaction to use. A ReadWrite transaction is required. Single-use
// transactions are not supported (to avoid replay). The caller must either
// supply an existing transaction ID or begin a new transaction.
TransactionSelector transaction = 2;

// The list of statements to execute in this batch. Statements are executed
// serially, such that the effects of statement i are visible to statement
// i+1. Each statement must be a DML statement. Execution will stop at the
// first failed statement; the remaining statements will not run.
//
// REQUIRES: statements_size() > 0.
repeated Statement statements = 3;

// A per-transaction sequence number used to identify this request. This is
// used in the same space as the seqno in
// [ExecuteSqlRequest][Spanner.ExecuteSqlRequest]. See more details
// in [ExecuteSqlRequest][Spanner.ExecuteSqlRequest].
int64 seqno = 4;
}

// The response for [ExecuteBatchDml][google.spanner.v1.Spanner.ExecuteBatchDml]. Contains a list
// of [ResultSet][google.spanner.v1.ResultSet], one for each DML statement that has successfully executed.
// If a statement fails, the error is returned as part of the response payload.
// Clients can determine whether all DML statements have run successfully, or if
// a statement failed, using one of the following approaches:
//
// 1. Check if 'status' field is OkStatus.
// 2. Check if result_sets_size() equals the number of statements in
// [ExecuteBatchDmlRequest][Spanner.ExecuteBatchDmlRequest].
//
// Example 1: A request with 5 DML statements, all executed successfully.
// Result: A response with 5 ResultSets, one for each statement in the same
// order, and an OK status.
//
// Example 2: A request with 5 DML statements. The 3rd statement has a syntax
// error.
// Result: A response with 2 ResultSets, for the first 2 statements that
// run successfully, and a syntax error (INVALID_ARGUMENT) status. From
// result_set_size() client can determine that the 3rd statement has failed.
message ExecuteBatchDmlResponse {
// ResultSets, one for each statement in the request that ran successfully, in
// the same order as the statements in the request. Each [ResultSet][google.spanner.v1.ResultSet] will
// not contain any rows. The [ResultSetStats][google.spanner.v1.ResultSetStats] in each [ResultSet][google.spanner.v1.ResultSet] will
// contain the number of rows modified by the statement.
//
// Only the first ResultSet in the response contains a valid
// [ResultSetMetadata][google.spanner.v1.ResultSetMetadata].
repeated ResultSet result_sets = 1;

// If all DML statements are executed successfully, status will be OK.
// Otherwise, the error status of the first failed statement.
google.rpc.Status status = 2;
}

// Options for a PartitionQueryRequest and
// PartitionReadRequest.
message PartitionOptions {
Expand Down
Loading