From d03f0045ce26b199d32d09194de9e6490ddf0f87 Mon Sep 17 00:00:00 2001 From: dpebot Date: Wed, 19 Sep 2018 04:10:02 -0700 Subject: [PATCH] Re-generate library using /synth.py --- .../database/v1/spanner_database_admin.proto | 2 +- .../instance/v1/spanner_instance_admin.proto | 2 +- protos/google/spanner/v1/keys.proto | 2 +- protos/google/spanner/v1/mutation.proto | 2 +- protos/google/spanner/v1/query_plan.proto | 2 +- protos/google/spanner/v1/result_set.proto | 25 +++++- protos/google/spanner/v1/spanner.proto | 68 ++++++++++---- protos/google/spanner/v1/transaction.proto | 84 +++++++++++++++-- protos/google/spanner/v1/type.proto | 2 +- .../doc/google/spanner/v1/doc_result_set.js | 20 ++++- src/v1/doc/google/spanner/v1/doc_spanner.js | 48 +++++++--- .../doc/google/spanner/v1/doc_transaction.js | 89 ++++++++++++++++-- src/v1/spanner_client.js | 90 +++++++++++++++---- 13 files changed, 367 insertions(+), 69 deletions(-) diff --git a/protos/google/spanner/admin/database/v1/spanner_database_admin.proto b/protos/google/spanner/admin/database/v1/spanner_database_admin.proto index 89f7343c8..56dbff19e 100644 --- a/protos/google/spanner/admin/database/v1/spanner_database_admin.proto +++ b/protos/google/spanner/admin/database/v1/spanner_database_admin.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/protos/google/spanner/admin/instance/v1/spanner_instance_admin.proto b/protos/google/spanner/admin/instance/v1/spanner_instance_admin.proto index 23d315bc1..e960e5428 100644 --- a/protos/google/spanner/admin/instance/v1/spanner_instance_admin.proto +++ b/protos/google/spanner/admin/instance/v1/spanner_instance_admin.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/protos/google/spanner/v1/keys.proto b/protos/google/spanner/v1/keys.proto index 463fb689c..2078610f3 100644 --- a/protos/google/spanner/v1/keys.proto +++ b/protos/google/spanner/v1/keys.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/protos/google/spanner/v1/mutation.proto b/protos/google/spanner/v1/mutation.proto index 30ab1e6e7..d4d5354c9 100644 --- a/protos/google/spanner/v1/mutation.proto +++ b/protos/google/spanner/v1/mutation.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/protos/google/spanner/v1/query_plan.proto b/protos/google/spanner/v1/query_plan.proto index 44c0dcf4c..7e82a404f 100644 --- a/protos/google/spanner/v1/query_plan.proto +++ b/protos/google/spanner/v1/query_plan.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/protos/google/spanner/v1/result_set.proto b/protos/google/spanner/v1/result_set.proto index ce3b3026f..152b1368a 100644 --- a/protos/google/spanner/v1/result_set.proto +++ b/protos/google/spanner/v1/result_set.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. @@ -45,8 +45,13 @@ message ResultSet { // [here][google.spanner.v1.TypeCode]. repeated google.protobuf.ListValue rows = 2; - // Query plan and execution statistics for the query that produced this - // result set. These can be requested by setting + // Query plan and execution statistics for the SQL statement that + // produced this result set. These can be requested by setting + // [ExecuteSqlRequest.query_mode][google.spanner.v1.ExecuteSqlRequest.query_mode]. + // DML statements always produce stats containing the number of rows + // modified, unless executed using the + // [ExecuteSqlRequest.QueryMode.PLAN][google.spanner.v1.ExecuteSqlRequest.QueryMode.PLAN] [ExecuteSqlRequest.query_mode][google.spanner.v1.ExecuteSqlRequest.query_mode]. + // Other fields may or may not be populated, based on the // [ExecuteSqlRequest.query_mode][google.spanner.v1.ExecuteSqlRequest.query_mode]. ResultSetStats stats = 3; } @@ -146,10 +151,12 @@ message PartialResultSet { // same session invalidates the token. bytes resume_token = 4; - // Query plan and execution statistics for the query that produced this + // Query plan and execution statistics for the statement that produced this // streaming result set. These can be requested by setting // [ExecuteSqlRequest.query_mode][google.spanner.v1.ExecuteSqlRequest.query_mode] and are sent // only once with the last response in the stream. + // This field will also be present in the last response for DML + // statements. ResultSetStats stats = 5; } @@ -185,4 +192,14 @@ message ResultSetStats { // "cpu_time": "1.19 secs" // } google.protobuf.Struct query_stats = 2; + + // The number of rows modified by the DML statement. + oneof row_count { + // Standard DML returns an exact count of rows that were modified. + int64 row_count_exact = 3; + + // Partitioned DML does not offer exactly-once semantics, so it + // returns a lower bound of the rows modified. + int64 row_count_lower_bound = 4; + } } diff --git a/protos/google/spanner/v1/spanner.proto b/protos/google/spanner/v1/spanner.proto index 30eecea9f..7d3de6ad7 100644 --- a/protos/google/spanner/v1/spanner.proto +++ b/protos/google/spanner/v1/spanner.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. @@ -88,12 +88,12 @@ service Spanner { }; } - // Executes an SQL query, returning all rows in a single reply. This + // Executes an SQL statement, returning all results in a single reply. This // method cannot be used to return a result set larger than 10 MiB; // if the query yields more data than that, the query fails with // a `FAILED_PRECONDITION` error. // - // Queries inside read-write transactions might return `ABORTED`. If + // Operations inside read-write transactions might return `ABORTED`. If // this occurs, the application should restart the transaction from // the beginning. See [Transaction][google.spanner.v1.Transaction] for more details. // @@ -197,8 +197,11 @@ service Spanner { // of the query result to read. The same session and read-only transaction // must be used by the PartitionQueryRequest used to create the // partition tokens and the ExecuteSqlRequests that use the partition tokens. + // // Partition tokens become invalid when the session used to create them - // is deleted or begins a new transaction. + // is deleted, is idle for too long, begins a new transaction, or becomes too + // old. When any of these happen, it is not possible to resume the query, and + // the whole operation must be restarted from the beginning. rpc PartitionQuery(PartitionQueryRequest) returns (PartitionResponse) { option (google.api.http) = { post: "/v1/{session=projects/*/instances/*/databases/*/sessions/*}:partitionQuery" @@ -211,9 +214,14 @@ service Spanner { // by [StreamingRead][google.spanner.v1.Spanner.StreamingRead] to specify a subset of the read // result to read. The same session and read-only transaction must be used by // the PartitionReadRequest used to create the partition tokens and the - // ReadRequests that use the partition tokens. + // ReadRequests that use the partition tokens. There are no ordering + // guarantees on rows returned among the returned partition tokens, or even + // within each individual StreamingRead call issued with a partition_token. + // // Partition tokens become invalid when the session used to create them - // is deleted or begins a new transaction. + // is deleted, is idle for too long, begins a new transaction, or becomes too + // old. When any of these happen, it is not possible to resume the read, and + // the whole operation must be restarted from the beginning. rpc PartitionRead(PartitionReadRequest) returns (PartitionResponse) { option (google.api.http) = { post: "/v1/{session=projects/*/instances/*/databases/*/sessions/*}:partitionRead" @@ -309,18 +317,17 @@ message DeleteSessionRequest { // The request for [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql] and // [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql]. message ExecuteSqlRequest { - // Mode in which the query must be processed. + // Mode in which the statement must be processed. enum QueryMode { - // The default mode where only the query result, without any information - // about the query plan is returned. + // The default mode. Only the statement results are returned. NORMAL = 0; - // This mode returns only the query plan, without any result rows or + // This mode returns only the query plan, without any results or // execution statistics information. PLAN = 1; // This mode returns both the query plan and the execution statistics along - // with the result rows. + // with the results. PROFILE = 2; } @@ -329,12 +336,23 @@ message ExecuteSqlRequest { // The transaction to use. If none is provided, the default is a // temporary read-only transaction with strong concurrency. + // + // The transaction to use. + // + // For queries, if none is provided, the default is a temporary read-only + // transaction with strong concurrency. + // + // Standard DML statements require a ReadWrite transaction. Single-use + // transactions are not supported (to avoid replay). The caller must + // either supply an existing transaction ID or begin a new transaction. + // + // Partitioned DML requires an existing PartitionedDml transaction ID. TransactionSelector transaction = 2; - // Required. The SQL query string. + // Required. The SQL string. string sql = 3; - // The SQL query string can contain parameter placeholders. A parameter + // The SQL 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. @@ -343,7 +361,7 @@ message ExecuteSqlRequest { // 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 query with unbound parameters. + // 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 @@ -355,15 +373,15 @@ message ExecuteSqlRequest { // of type `STRING` both appear in [params][google.spanner.v1.ExecuteSqlRequest.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 query parameters. See the + // 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 param_types = 5; - // If this request is resuming a previously interrupted SQL query + // If this request is resuming a previously interrupted SQL statement // execution, `resume_token` should be copied from the last // [PartialResultSet][google.spanner.v1.PartialResultSet] yielded before the interruption. Doing this - // enables the new SQL query execution to resume where the last one left + // enables the new SQL statement execution to resume where the last one left // off. The rest of the request parameters must exactly match the // request that yielded this token. bytes resume_token = 6; @@ -378,6 +396,18 @@ message ExecuteSqlRequest { // match for the values of fields common to this message and the // PartitionQueryRequest message used to create this partition_token. bytes partition_token = 8; + + // A per-transaction sequence number used to identify this request. This + // makes each request idempotent such that if the request is received multiple + // times, at most one will succeed. + // + // The sequence number must be monotonically increasing within the + // transaction. If a request arrives for the first time with an out-of-order + // sequence number, the transaction may be aborted. Replays of previously + // handled requests will yield the same response as the first execution. + // + // Required for DML statements. Ignored for queries. + int64 seqno = 9; } // Options for a PartitionQueryRequest and @@ -417,6 +447,10 @@ message PartitionQueryRequest { // union operator conceptually divides one or more tables into multiple // splits, remotely evaluates a subquery independently on each split, and // then unions all results. + // + // This must not contain DML commands, such as INSERT, UPDATE, or + // DELETE. Use [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql] with a + // PartitionedDml transaction for large, partition-friendly DML operations. string sql = 3; // The SQL query string can contain parameter placeholders. A parameter diff --git a/protos/google/spanner/v1/transaction.proto b/protos/google/spanner/v1/transaction.proto index d4eb7f956..e7fafc0e7 100644 --- a/protos/google/spanner/v1/transaction.proto +++ b/protos/google/spanner/v1/transaction.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. @@ -38,7 +38,7 @@ option php_namespace = "Google\\Cloud\\Spanner\\V1"; // // # Transaction Modes // -// Cloud Spanner supports two transaction modes: +// Cloud Spanner supports three transaction modes: // // 1. Locking read-write. This type of transaction is the only way // to write data into Cloud Spanner. These transactions rely on @@ -52,6 +52,13 @@ option php_namespace = "Google\\Cloud\\Spanner\\V1"; // read at timestamps in the past. Snapshot read-only // transactions do not need to be committed. // +// 3. Partitioned DML. This type of transaction is used to execute +// a single Partitioned DML statement. Partitioned DML partitions +// the key space and runs the DML statement over each partition +// in parallel using separate, internal transactions that commit +// independently. Partitioned DML transactions do not need to be +// committed. +// // For transactions that only read, snapshot read-only transactions // provide simpler semantics and are almost always faster. In // particular, read-only transactions do not take locks, so they do @@ -78,11 +85,8 @@ option php_namespace = "Google\\Cloud\\Spanner\\V1"; // inactivity at the client may cause Cloud Spanner to release a // transaction's locks and abort it. // -// Reads performed within a transaction acquire locks on the data -// being read. Writes can only be done at commit time, after all reads -// have been completed. // Conceptually, a read-write transaction consists of zero or more -// reads or SQL queries followed by +// reads or SQL statements followed by // [Commit][google.spanner.v1.Spanner.Commit]. At any time before // [Commit][google.spanner.v1.Spanner.Commit], the client can send a // [Rollback][google.spanner.v1.Spanner.Rollback] request to abort the @@ -245,6 +249,62 @@ option php_namespace = "Google\\Cloud\\Spanner\\V1"; // restriction also applies to in-progress reads and/or SQL queries whose // timestamp become too old while executing. Reads and SQL queries with // too-old read timestamps fail with the error `FAILED_PRECONDITION`. +// +// ## Partitioned DML Transactions +// +// Partitioned DML transactions are used to execute DML statements with a +// different execution strategy that provides different, and often better, +// scalability properties for large, table-wide operations than DML in a +// ReadWrite transaction. Smaller scoped statements, such as an OLTP workload, +// should prefer using ReadWrite transactions. +// +// Partitioned DML partitions the keyspace and runs the DML statement on each +// partition in separate, internal transactions. These transactions commit +// automatically when complete, and run independently from one another. +// +// To reduce lock contention, this execution strategy only acquires read locks +// on rows that match the WHERE clause of the statement. Additionally, the +// smaller per-partition transactions hold locks for less time. +// +// That said, Partitioned DML is not a drop-in replacement for standard DML used +// in ReadWrite transactions. +// +// - The DML statement must be fully-partitionable. Specifically, the statement +// must be expressible as the union of many statements which each access only +// a single row of the table. +// +// - The statement is not applied atomically to all rows of the table. Rather, +// the statement is applied atomically to partitions of the table, in +// independent transactions. Secondary index rows are updated atomically +// with the base table rows. +// +// - Partitioned DML does not guarantee exactly-once execution semantics +// against a partition. The statement will be applied at least once to each +// partition. It is strongly recommended that the DML statement should be +// idempotent to avoid unexpected results. For instance, it is potentially +// dangerous to run a statement such as +// `UPDATE table SET column = column + 1` as it could be run multiple times +// against some rows. +// +// - The partitions are committed automatically - there is no support for +// Commit or Rollback. If the call returns an error, or if the client issuing +// the ExecuteSql call dies, it is possible that some rows had the statement +// executed on them successfully. It is also possible that statement was +// never executed against other rows. +// +// - Partitioned DML transactions may only contain the execution of a single +// DML statement via ExecuteSql or ExecuteStreamingSql. +// +// - If any error is encountered during the execution of the partitioned DML +// operation (for instance, a UNIQUE INDEX violation, division by zero, or a +// value that cannot be stored due to schema constraints), then the +// operation is stopped at that point and an error is returned. It is +// possible that at this point, some partitions have been committed (or even +// committed multiple times), and other partitions have not been run at all. +// +// Given the above, Partitioned DML is good fit for large, database-wide, +// operations that are idempotent, such as deleting old rows from a very large +// table. message TransactionOptions { // Message type to initiate a read-write transaction. Currently this // transaction type has no options. @@ -252,6 +312,11 @@ message TransactionOptions { } + // Message type to initiate a Partitioned DML transaction. + message PartitionedDml { + + } + // Message type to initiate a read-only transaction. message ReadOnly { // How to choose the timestamp for the read-only transaction. @@ -329,6 +394,13 @@ message TransactionOptions { // on the `session` resource. ReadWrite read_write = 1; + // Partitioned DML transaction. + // + // Authorization to begin a Partitioned DML transaction requires + // `spanner.databases.beginPartitionedDmlTransaction` permission + // on the `session` resource. + PartitionedDml partitioned_dml = 3; + // Transaction will not write. // // Authorization to begin a read-only transaction requires diff --git a/protos/google/spanner/v1/type.proto b/protos/google/spanner/v1/type.proto index 048cc0b07..de5203dd5 100644 --- a/protos/google/spanner/v1/type.proto +++ b/protos/google/spanner/v1/type.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. +// 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. diff --git a/src/v1/doc/google/spanner/v1/doc_result_set.js b/src/v1/doc/google/spanner/v1/doc_result_set.js index a468fc92c..2ef950d49 100644 --- a/src/v1/doc/google/spanner/v1/doc_result_set.js +++ b/src/v1/doc/google/spanner/v1/doc_result_set.js @@ -35,8 +35,13 @@ * This object should have the same structure as [ListValue]{@link google.protobuf.ListValue} * * @property {Object} stats - * Query plan and execution statistics for the query that produced this - * result set. These can be requested by setting + * Query plan and execution statistics for the SQL statement that + * produced this result set. These can be requested by setting + * ExecuteSqlRequest.query_mode. + * DML statements always produce stats containing the number of rows + * modified, unless executed using the + * ExecuteSqlRequest.QueryMode.PLAN ExecuteSqlRequest.query_mode. + * Other fields may or may not be populated, based on the * ExecuteSqlRequest.query_mode. * * This object should have the same structure as [ResultSetStats]{@link google.spanner.v1.ResultSetStats} @@ -150,10 +155,12 @@ const ResultSet = { * same session invalidates the token. * * @property {Object} stats - * Query plan and execution statistics for the query that produced this + * Query plan and execution statistics for the statement that produced this * streaming result set. These can be requested by setting * ExecuteSqlRequest.query_mode and are sent * only once with the last response in the stream. + * This field will also be present in the last response for DML + * statements. * * This object should have the same structure as [ResultSetStats]{@link google.spanner.v1.ResultSetStats} * @@ -215,6 +222,13 @@ const ResultSetMetadata = { * * This object should have the same structure as [Struct]{@link google.protobuf.Struct} * + * @property {number} rowCountExact + * Standard DML returns an exact count of rows that were modified. + * + * @property {number} rowCountLowerBound + * Partitioned DML does not offer exactly-once semantics, so it + * returns a lower bound of the rows modified. + * * @typedef ResultSetStats * @memberof google.spanner.v1 * @see [google.spanner.v1.ResultSetStats definition in proto format]{@link https://github.com/googleapis/googleapis/blob/master/google/spanner/v1/result_set.proto} diff --git a/src/v1/doc/google/spanner/v1/doc_spanner.js b/src/v1/doc/google/spanner/v1/doc_spanner.js index 6fcb4971a..d66cfae04 100644 --- a/src/v1/doc/google/spanner/v1/doc_spanner.js +++ b/src/v1/doc/google/spanner/v1/doc_spanner.js @@ -166,13 +166,24 @@ const DeleteSessionRequest = { * The transaction to use. If none is provided, the default is a * temporary read-only transaction with strong concurrency. * + * The transaction to use. + * + * For queries, if none is provided, the default is a temporary read-only + * transaction with strong concurrency. + * + * Standard DML statements require a ReadWrite transaction. Single-use + * transactions are not supported (to avoid replay). The caller must + * either supply an existing transaction ID or begin a new transaction. + * + * Partitioned DML requires an existing PartitionedDml transaction ID. + * * This object should have the same structure as [TransactionSelector]{@link google.spanner.v1.TransactionSelector} * * @property {string} sql - * Required. The SQL query string. + * Required. The SQL string. * * @property {Object} params - * The SQL query string can contain parameter placeholders. A parameter + * The SQL 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. @@ -181,7 +192,7 @@ const DeleteSessionRequest = { * 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 query with unbound parameters. + * 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 @@ -195,15 +206,15 @@ const DeleteSessionRequest = { * of type `STRING` both appear in 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 query parameters. See the + * SQL type for some or all of the SQL statement parameters. See the * definition of Type for more information * about SQL types. * * @property {string} resumeToken - * If this request is resuming a previously interrupted SQL query + * If this request is resuming a previously interrupted SQL statement * execution, `resume_token` should be copied from the last * PartialResultSet yielded before the interruption. Doing this - * enables the new SQL query execution to resume where the last one left + * enables the new SQL statement execution to resume where the last one left * off. The rest of the request parameters must exactly match the * request that yielded this token. * @@ -220,6 +231,18 @@ const DeleteSessionRequest = { * match for the values of fields common to this message and the * PartitionQueryRequest message used to create this partition_token. * + * @property {number} seqno + * A per-transaction sequence number used to identify this request. This + * makes each request idempotent such that if the request is received multiple + * times, at most one will succeed. + * + * The sequence number must be monotonically increasing within the + * transaction. If a request arrives for the first time with an out-of-order + * sequence number, the transaction may be aborted. Replays of previously + * handled requests will yield the same response as the first execution. + * + * Required for DML statements. Ignored for queries. + * * @typedef ExecuteSqlRequest * @memberof google.spanner.v1 * @see [google.spanner.v1.ExecuteSqlRequest definition in proto format]{@link https://github.com/googleapis/googleapis/blob/master/google/spanner/v1/spanner.proto} @@ -228,7 +251,7 @@ const ExecuteSqlRequest = { // This is for documentation. Actual contents will be loaded by gRPC. /** - * Mode in which the query must be processed. + * Mode in which the statement must be processed. * * @enum {number} * @memberof google.spanner.v1 @@ -236,20 +259,19 @@ const ExecuteSqlRequest = { QueryMode: { /** - * The default mode where only the query result, without any information - * about the query plan is returned. + * The default mode. Only the statement results are returned. */ NORMAL: 0, /** - * This mode returns only the query plan, without any result rows or + * This mode returns only the query plan, without any results or * execution statistics information. */ PLAN: 1, /** * This mode returns both the query plan and the execution statistics along - * with the result rows. + * with the results. */ PROFILE: 2 } @@ -305,6 +327,10 @@ const PartitionOptions = { * splits, remotely evaluates a subquery independently on each split, and * then unions all results. * + * This must not contain DML commands, such as INSERT, UPDATE, or + * DELETE. Use ExecuteStreamingSql with a + * PartitionedDml transaction for large, partition-friendly DML operations. + * * @property {Object} params * The SQL query string can contain parameter placeholders. A parameter * placeholder consists of `'@'` followed by the parameter diff --git a/src/v1/doc/google/spanner/v1/doc_transaction.js b/src/v1/doc/google/spanner/v1/doc_transaction.js index 36af00019..a77e967d5 100644 --- a/src/v1/doc/google/spanner/v1/doc_transaction.js +++ b/src/v1/doc/google/spanner/v1/doc_transaction.js @@ -25,7 +25,7 @@ * * # Transaction Modes * - * Cloud Spanner supports two transaction modes: + * Cloud Spanner supports three transaction modes: * * 1. Locking read-write. This type of transaction is the only way * to write data into Cloud Spanner. These transactions rely on @@ -39,6 +39,13 @@ * read at timestamps in the past. Snapshot read-only * transactions do not need to be committed. * + * 3. Partitioned DML. This type of transaction is used to execute + * a single Partitioned DML statement. Partitioned DML partitions + * the key space and runs the DML statement over each partition + * in parallel using separate, internal transactions that commit + * independently. Partitioned DML transactions do not need to be + * committed. + * * For transactions that only read, snapshot read-only transactions * provide simpler semantics and are almost always faster. In * particular, read-only transactions do not take locks, so they do @@ -65,11 +72,8 @@ * inactivity at the client may cause Cloud Spanner to release a * transaction's locks and abort it. * - * Reads performed within a transaction acquire locks on the data - * being read. Writes can only be done at commit time, after all reads - * have been completed. * Conceptually, a read-write transaction consists of zero or more - * reads or SQL queries followed by + * reads or SQL statements followed by * Commit. At any time before * Commit, the client can send a * Rollback request to abort the @@ -233,6 +237,62 @@ * timestamp become too old while executing. Reads and SQL queries with * too-old read timestamps fail with the error `FAILED_PRECONDITION`. * + * ## Partitioned DML Transactions + * + * Partitioned DML transactions are used to execute DML statements with a + * different execution strategy that provides different, and often better, + * scalability properties for large, table-wide operations than DML in a + * ReadWrite transaction. Smaller scoped statements, such as an OLTP workload, + * should prefer using ReadWrite transactions. + * + * Partitioned DML partitions the keyspace and runs the DML statement on each + * partition in separate, internal transactions. These transactions commit + * automatically when complete, and run independently from one another. + * + * To reduce lock contention, this execution strategy only acquires read locks + * on rows that match the WHERE clause of the statement. Additionally, the + * smaller per-partition transactions hold locks for less time. + * + * That said, Partitioned DML is not a drop-in replacement for standard DML used + * in ReadWrite transactions. + * + * - The DML statement must be fully-partitionable. Specifically, the statement + * must be expressible as the union of many statements which each access only + * a single row of the table. + * + * - The statement is not applied atomically to all rows of the table. Rather, + * the statement is applied atomically to partitions of the table, in + * independent transactions. Secondary index rows are updated atomically + * with the base table rows. + * + * - Partitioned DML does not guarantee exactly-once execution semantics + * against a partition. The statement will be applied at least once to each + * partition. It is strongly recommended that the DML statement should be + * idempotent to avoid unexpected results. For instance, it is potentially + * dangerous to run a statement such as + * `UPDATE table SET column = column + 1` as it could be run multiple times + * against some rows. + * + * - The partitions are committed automatically - there is no support for + * Commit or Rollback. If the call returns an error, or if the client issuing + * the ExecuteSql call dies, it is possible that some rows had the statement + * executed on them successfully. It is also possible that statement was + * never executed against other rows. + * + * - Partitioned DML transactions may only contain the execution of a single + * DML statement via ExecuteSql or ExecuteStreamingSql. + * + * - If any error is encountered during the execution of the partitioned DML + * operation (for instance, a UNIQUE INDEX violation, division by zero, or a + * value that cannot be stored due to schema constraints), then the + * operation is stopped at that point and an error is returned. It is + * possible that at this point, some partitions have been committed (or even + * committed multiple times), and other partitions have not been run at all. + * + * Given the above, Partitioned DML is good fit for large, database-wide, + * operations that are idempotent, such as deleting old rows from a very large + * table. + * * @property {Object} readWrite * Transaction may write. * @@ -242,6 +302,15 @@ * * This object should have the same structure as [ReadWrite]{@link google.spanner.v1.ReadWrite} * + * @property {Object} partitionedDml + * Partitioned DML transaction. + * + * Authorization to begin a Partitioned DML transaction requires + * `spanner.databases.beginPartitionedDmlTransaction` permission + * on the `session` resource. + * + * This object should have the same structure as [PartitionedDml]{@link google.spanner.v1.PartitionedDml} + * * @property {Object} readOnly * Transaction will not write. * @@ -269,6 +338,16 @@ const TransactionOptions = { // This is for documentation. Actual contents will be loaded by gRPC. }, + /** + * Message type to initiate a Partitioned DML transaction. + * @typedef PartitionedDml + * @memberof google.spanner.v1 + * @see [google.spanner.v1.TransactionOptions.PartitionedDml definition in proto format]{@link https://github.com/googleapis/googleapis/blob/master/google/spanner/v1/transaction.proto} + */ + PartitionedDml: { + // This is for documentation. Actual contents will be loaded by gRPC. + }, + /** * Message type to initiate a read-only transaction. * diff --git a/src/v1/spanner_client.js b/src/v1/spanner_client.js index 2ee23413b..21ab358b8 100644 --- a/src/v1/spanner_client.js +++ b/src/v1/spanner_client.js @@ -548,12 +548,12 @@ class SpannerClient { } /** - * Executes an SQL query, returning all rows in a single reply. This + * Executes an SQL statement, returning all results in a single reply. This * method cannot be used to return a result set larger than 10 MiB; * if the query yields more data than that, the query fails with * a `FAILED_PRECONDITION` error. * - * Queries inside read-write transactions might return `ABORTED`. If + * Operations inside read-write transactions might return `ABORTED`. If * this occurs, the application should restart the transaction from * the beginning. See Transaction for more details. * @@ -565,14 +565,25 @@ class SpannerClient { * @param {string} request.session * Required. The session in which the SQL query should be performed. * @param {string} request.sql - * Required. The SQL query string. + * Required. The SQL string. * @param {Object} [request.transaction] * The transaction to use. If none is provided, the default is a * temporary read-only transaction with strong concurrency. * + * The transaction to use. + * + * For queries, if none is provided, the default is a temporary read-only + * transaction with strong concurrency. + * + * Standard DML statements require a ReadWrite transaction. Single-use + * transactions are not supported (to avoid replay). The caller must + * either supply an existing transaction ID or begin a new transaction. + * + * Partitioned DML requires an existing PartitionedDml transaction ID. + * * This object should have the same structure as [TransactionSelector]{@link google.spanner.v1.TransactionSelector} * @param {Object} [request.params] - * The SQL query string can contain parameter placeholders. A parameter + * The SQL 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. @@ -581,7 +592,7 @@ class SpannerClient { * 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 query with unbound parameters. + * 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 @@ -594,14 +605,14 @@ class SpannerClient { * of type `STRING` both appear in 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 query parameters. See the + * SQL type for some or all of the SQL statement parameters. See the * definition of Type for more information * about SQL types. * @param {string} [request.resumeToken] - * If this request is resuming a previously interrupted SQL query + * If this request is resuming a previously interrupted SQL statement * execution, `resume_token` should be copied from the last * PartialResultSet yielded before the interruption. Doing this - * enables the new SQL query execution to resume where the last one left + * enables the new SQL statement execution to resume where the last one left * off. The rest of the request parameters must exactly match the * request that yielded this token. * @param {number} [request.queryMode] @@ -615,6 +626,17 @@ class SpannerClient { * previously created using PartitionQuery(). There must be an exact * match for the values of fields common to this message and the * PartitionQueryRequest message used to create this partition_token. + * @param {number} [request.seqno] + * A per-transaction sequence number used to identify this request. This + * makes each request idempotent such that if the request is received multiple + * times, at most one will succeed. + * + * The sequence number must be monotonically increasing within the + * transaction. If a request arrives for the first time with an out-of-order + * sequence number, the transaction may be aborted. Replays of previously + * handled requests will yield the same response as the first execution. + * + * Required for DML statements. Ignored for queries. * @param {Object} [options] * Optional parameters. You can override the default settings for this call, e.g, timeout, * retries, paginations, etc. See [gax.CallOptions]{@link https://googleapis.github.io/gax-nodejs/global.html#CallOptions} for the details. @@ -671,14 +693,25 @@ class SpannerClient { * @param {string} request.session * Required. The session in which the SQL query should be performed. * @param {string} request.sql - * Required. The SQL query string. + * Required. The SQL string. * @param {Object} [request.transaction] * The transaction to use. If none is provided, the default is a * temporary read-only transaction with strong concurrency. * + * The transaction to use. + * + * For queries, if none is provided, the default is a temporary read-only + * transaction with strong concurrency. + * + * Standard DML statements require a ReadWrite transaction. Single-use + * transactions are not supported (to avoid replay). The caller must + * either supply an existing transaction ID or begin a new transaction. + * + * Partitioned DML requires an existing PartitionedDml transaction ID. + * * This object should have the same structure as [TransactionSelector]{@link google.spanner.v1.TransactionSelector} * @param {Object} [request.params] - * The SQL query string can contain parameter placeholders. A parameter + * The SQL 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. @@ -687,7 +720,7 @@ class SpannerClient { * 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 query with unbound parameters. + * 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 @@ -700,14 +733,14 @@ class SpannerClient { * of type `STRING` both appear in 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 query parameters. See the + * SQL type for some or all of the SQL statement parameters. See the * definition of Type for more information * about SQL types. * @param {string} [request.resumeToken] - * If this request is resuming a previously interrupted SQL query + * If this request is resuming a previously interrupted SQL statement * execution, `resume_token` should be copied from the last * PartialResultSet yielded before the interruption. Doing this - * enables the new SQL query execution to resume where the last one left + * enables the new SQL statement execution to resume where the last one left * off. The rest of the request parameters must exactly match the * request that yielded this token. * @param {number} [request.queryMode] @@ -721,6 +754,17 @@ class SpannerClient { * previously created using PartitionQuery(). There must be an exact * match for the values of fields common to this message and the * PartitionQueryRequest message used to create this partition_token. + * @param {number} [request.seqno] + * A per-transaction sequence number used to identify this request. This + * makes each request idempotent such that if the request is received multiple + * times, at most one will succeed. + * + * The sequence number must be monotonically increasing within the + * transaction. If a request arrives for the first time with an out-of-order + * sequence number, the transaction may be aborted. Replays of previously + * handled requests will yield the same response as the first execution. + * + * Required for DML statements. Ignored for queries. * @param {Object} [options] * Optional parameters. You can override the default settings for this call, e.g, timeout, * retries, paginations, etc. See [gax.CallOptions]{@link https://googleapis.github.io/gax-nodejs/global.html#CallOptions} for the details. @@ -1148,8 +1192,11 @@ class SpannerClient { * of the query result to read. The same session and read-only transaction * must be used by the PartitionQueryRequest used to create the * partition tokens and the ExecuteSqlRequests that use the partition tokens. + * * Partition tokens become invalid when the session used to create them - * is deleted or begins a new transaction. + * is deleted, is idle for too long, begins a new transaction, or becomes too + * old. When any of these happen, it is not possible to resume the query, and + * the whole operation must be restarted from the beginning. * * @param {Object} request * The request object that will be sent. @@ -1162,6 +1209,10 @@ class SpannerClient { * union operator conceptually divides one or more tables into multiple * splits, remotely evaluates a subquery independently on each split, and * then unions all results. + * + * This must not contain DML commands, such as INSERT, UPDATE, or + * DELETE. Use ExecuteStreamingSql with a + * PartitionedDml transaction for large, partition-friendly DML operations. * @param {Object} [request.transaction] * Read only snapshot transactions are supported, read/write and single use * transactions are not. @@ -1247,9 +1298,14 @@ class SpannerClient { * by StreamingRead to specify a subset of the read * result to read. The same session and read-only transaction must be used by * the PartitionReadRequest used to create the partition tokens and the - * ReadRequests that use the partition tokens. + * ReadRequests that use the partition tokens. There are no ordering + * guarantees on rows returned among the returned partition tokens, or even + * within each individual StreamingRead call issued with a partition_token. + * * Partition tokens become invalid when the session used to create them - * is deleted or begins a new transaction. + * is deleted, is idle for too long, begins a new transaction, or becomes too + * old. When any of these happen, it is not possible to resume the read, and + * the whole operation must be restarted from the beginning. * * @param {Object} request * The request object that will be sent.