From a2a8ce5678147bc95c55c058140719a469569010 Mon Sep 17 00:00:00 2001 From: Jack Coulter Date: Wed, 28 Jun 2017 11:20:29 +1000 Subject: [PATCH] spanner: Properly handle multi-row mutations with heterogeneous columns Prior to this change, attempting to insert multiple rows at once with Table#insert or Transaction#insert where some rows lack a value for nullable columns would result in data attempting to be inserted into the incorrect column, due to a flawed assumption in transaction-request.js that every single row contains exact same set of columns, and that the order of keys returned by Object.keys would be identical for each and every row. This fixes #2411. --- packages/spanner/src/transaction-request.js | 23 ++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/spanner/src/transaction-request.js b/packages/spanner/src/transaction-request.js index e195db8ab68..f796873d752 100644 --- a/packages/spanner/src/transaction-request.js +++ b/packages/spanner/src/transaction-request.js @@ -684,12 +684,29 @@ TransactionRequest.prototype.mutate_ = function(method, table, keyVals, cb) { var mutation = {}; + var columns = keyVals.reduce(function(allKeys, keyVal) { + var keys = Object.keys(keyVal); + var key; + + for (var i = 0, ii = keys.length; i < ii; ++i) { + key = keys[i]; + + if (allKeys.indexOf(key) === -1) { + allKeys.push(key); + } + } + + return allKeys; + }, []).sort(); + mutation[method] = { table: table, - columns: Object.keys(keyVals[0]), + columns: columns, values: keyVals.map(function(keyVal) { - return Object.keys(keyVal).map(function(key) { - return codec.encode(keyVal[key]); + return columns.map(function(key) { + var value = keyVal[key]; + + return codec.encode(value === undefined ? null : value); }); }) };