diff --git a/Spanner/src/Transaction.php b/Spanner/src/Transaction.php
index 787ba99dd291..7c721ad56ad9 100644
--- a/Spanner/src/Transaction.php
+++ b/Spanner/src/Transaction.php
@@ -312,7 +312,9 @@ public function delete($table, KeySet $keySet)
*
* Data Manipulation Language (DML) allows you to execute statements which
* modify the state of the database (i.e. inserting, updating or deleting
- * rows).
+ * rows). DML supports INSERT, UPDATE and DELETE statements. For
+ * more on DML syntax, visit the
+ * [DML syntax guide](https://cloud.google.com/spanner/docs/dml-syntax).
*
* To execute a SQL query (such as a SELECT), use
* {@see Google\Cloud\Spanner\Transaction::execute()}.
@@ -333,8 +335,32 @@ public function delete($table, KeySet $keySet)
* ]);
* ```
*
+ * ```
+ * // Example of executeUpdate while using DML Structs
+ * $statement = "UPDATE Posts SET title = 'Updated Title' " .
+ * "WHERE STRUCT
(Title, Content) = @post";
+ *
+ * $postValue = new StructValue();
+ * $postValue->add('Title', 'Updated Title')
+ * ->add('Content', 'Sample Content');
+ *
+ * $postType = new StructType();
+ * $postType->add('Title', Database::TYPE_STRING)
+ * ->add('Content', Database::TYPE_STRING);
+ *
+ * $modifiedRowCount = $transaction->executeUpdate($statement, [
+ * 'parameters' => [
+ * 'post' => $postValue
+ * ],
+ * 'types' => [
+ * 'post' => $postType
+ * ]
+ * ]);
+ * ```
+ *
* @codingStandardsIgnoreStart
* @see https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest ExecuteSqlRequest
+ * @see https://cloud.google.com/spanner/docs/dml-syntax DML Syntax Guide
* @codingStandardsIgnoreEnd
*
* @param string $sql The query string to execute.
diff --git a/Spanner/tests/Snippet/TransactionTest.php b/Spanner/tests/Snippet/TransactionTest.php
index 3fe11d959eca..8104de966826 100644
--- a/Spanner/tests/Snippet/TransactionTest.php
+++ b/Spanner/tests/Snippet/TransactionTest.php
@@ -26,6 +26,8 @@
use Google\Cloud\Spanner\Operation;
use Google\Cloud\Spanner\Result;
use Google\Cloud\Spanner\Session\Session;
+use Google\Cloud\Spanner\StructType;
+use Google\Cloud\Spanner\StructValue;
use Google\Cloud\Spanner\Tests\OperationRefreshTrait;
use Google\Cloud\Spanner\Tests\ResultGeneratorTrait;
use Google\Cloud\Spanner\Timestamp;
@@ -116,6 +118,61 @@ public function testExecuteUpdate()
$this->assertEquals(1, $res->returnVal());
}
+ public function testExecuteUpdateWithStruct()
+ {
+ $expectedSql = "UPDATE Posts SET title = 'Updated Title' WHERE " .
+ "STRUCT(Title, Content) = @post";
+
+ $expectedParams = [
+ 'post' => ["Updated Title", "Sample Content"]
+ ];
+ $expectedStructData = [
+ [
+ "name" => "Title",
+ "type" => [
+ "code" => Database::TYPE_STRING
+ ]
+ ],
+ [
+ "name" => "Content",
+ "type" => [
+ "code" => Database::TYPE_STRING
+ ]
+ ]
+ ];
+
+ $this->connection->executeStreamingSql(
+ Argument::allOf(
+ Argument::withEntry('sql', $expectedSql),
+ Argument::withEntry('params', $expectedParams),
+ Argument::withEntry(
+ 'paramTypes',
+ Argument::withEntry(
+ 'post',
+ Argument::withEntry(
+ 'structType',
+ Argument::withEntry('fields', Argument::is($expectedStructData))
+ )
+ )
+ )
+ )
+ )
+ ->shouldBeCalled()
+ ->willReturn($this->resultGenerator(true));
+
+ $this->refreshOperation($this->transaction, $this->connection->reveal());
+
+ $snippet = $this->snippetFromMethod(Transaction::class, 'executeUpdate', 1);
+ $snippet->addUse(Database::class);
+ $snippet->addUse(StructType::class);
+ $snippet->addUse(StructValue::class);
+
+ $snippet->addLocal('transaction', $this->transaction);
+ $res = $snippet->invoke('modifiedRowCount');
+
+ $this->assertEquals(1, $res->returnVal());
+ }
+
public function testExecuteUpdateBatch()
{
$this->connection->executeBatchDml(Argument::any())